请考虑以下代码:
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。