C# 如何在TaskCompletionSource.task内将同步上下文/任务计划程序替换为另一个用于ConfigureWait(false)的同步上下文/任务计划程序?

C# 如何在TaskCompletionSource.task内将同步上下文/任务计划程序替换为另一个用于ConfigureWait(false)的同步上下文/任务计划程序?,c#,multithreading,async-await,task-parallel-library,taskcompletionsource,C#,Multithreading,Async Await,Task Parallel Library,Taskcompletionsource,假设我创建了一个包含以下方法的库: Task MyLibraryMethodAsync() { var taskCompletionSource = new TaskCompletionSource<object>(); Action myWorkItem = () => { // Simulate some work. // Actual work items depend on

假设我创建了一个包含以下方法的库:

Task MyLibraryMethodAsync()
{
    var taskCompletionSource = new TaskCompletionSource<object>();

    Action myWorkItem =
        () =>
        {
            // Simulate some work.
            // Actual work items depend on input params.
            Thread.Sleep(TimeSpan.FromSeconds(1));

            taskCompletionSource.SetResult(null);
        };

    // The next two lines is simplification for demonstration.
    // I do not have access to the workerThread - it is created
    // and managed for me by another lib.
    // All I can do - is to post some short work items to it.
    var workerThread = new Thread(new ThreadStart(myWorkItem));
    workerThread.Start();

    return taskCompletionSource.Task;
}
void VeryLongRunningMethod()
{
线程。睡眠(时间跨度从小时(1));
}
问题来了–
VeryLongRunningMethod
将在
taskCompletionSource.SetResult(null)
调用中执行,因此它将阻塞
workerThread
很长一段时间,这不是期望的行为,因为
workerThread
旨在运行代码的一小部分(工作项)

如何将上下文/调度程序替换为返回任务中的线程池,使
等待x.ConfigureAwait(false)
线程池上继续,而不是在
workerThread
上继续

目前我找到的解决方案是

Task MyLibraryMethodAsync()
{
    // ...

    return taskCompletionSource.Task
        .ContinueWith(x => x.Result, TaskScheduler.Default);
}
然而,我不喜欢它,因为它会造成开销。
是否存在更优雅的解决方案?

不确定我是否正确理解您,但您可以显式创建后台任务以避免阻塞:

await MyLibraryMethodAsync().ConfigureAwait(false);
await Task.Run(() => VeryLongRunningMethod());
您甚至可以省略ConfigureWait,然后:

await MyLibraryMethodAsync()
await Task.Run(() => VeryLongRunningMethod());
编辑:根据您的评论:如果您作为库的作者想要防止阻止线程,您可以使用:

Task.Run(() => taskCompletionSource.SetResult(null));

从.NET 4.6开始,
TaskCreationOptions
中有一个名为
RunContinuationsAsynchronously
的选项,它完全满足您的需要,它确保所有continuations异步运行,而不是在设置结果时同步运行
TaskCompletionSource
在其构造函数中有一个可选的
TaskCreationOption
参数,供您提供该选项


如果您使用的是早期版本的.NET,则需要进行效率较低的黑客攻击,例如添加另一个延续,如图所示,或者在线程池线程中显式设置结果,而不是通过回调操作。

从用户的角度看,您是对的。但我是lib开发人员,我需要确保lib用户无论如何都不会阻止工作线程;要设置结果?这将产生与我当前解决方案相同的开销。不管怎样,Servy解决了我的问题。
Task.Run(() => taskCompletionSource.SetResult(null));