请考虑以下代码:

public Task SomeAsyncMethod()
{
    var tcs = new TaskCompletionSource();
    ... do something, NOT setting the TaskCompletionSource...

    return tcs.Task
}

public void Callsite1()
{
    await SomeAsyncMethod();
    Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
}

public void Callsite2()
{
    SomeAsyncMethod().ContinueWith((task) =>
    {
        Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
    });
}

在某个时间点,在SomeAsyncMethod中创建的taskCompletionSource设置在线程池线程上:
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
tcs.SetResult();

当等待来自taskCompletionSource的任务时(如callsite1中所示),continuation将在调用setResult的线程上同步执行。当调用continueWith(如callsite2中所述)时,continuation将在不同的线程上异步执行。
调用configure the await没有帮助,如
public void Callsite1()
{
    await SomeAsyncMethod().ConfigureAwait(true or false);
}

这甚至不是这个问题的重点。作为SomeAsyncMethod的实现者,我不想通过调用setResult来调用一些潜在的未知代码。我想让continuation总是异步调度的。而且我不能依赖调用者正确地配置等待(如果这样做可以的话)。
如何配置taskCompletionSource,使其任务在等待时不会同步执行其continuation?

最佳答案

无法阻止同步任务继续。通常,这不是问题。
但是,在某些情况下,您确实需要这样做,例如,如果您在持有锁的情况下完成任务。在这些情况下,您只需Task.Run任务完成即可,例如:

// Set the result on a threadpool thread, so any synchronous continuations
//  will execute in the background.
Task.Run(() => tcs.TrySetResult(result));

// Wait for the TCS task to complete; note that the continuations
//  may not be complete.
tcs.Task.Wait();

这是一种先进的技术。这是guideline "Don't block on async code (async all the way down)" as expounded on my blog的一个例外。
它是我的AsyncEx library的一部分,作为一种扩展方法:
public static void TrySetResultWithBackgroundContinuations<TResult>(
    this TaskCompletionSource<TResult> @this, TResult result);

这项技术是first published by Stephen Toub on his blog

09-11 04:12