假设我有一个 Task
生成 int
,以及接受 int
的回调:
Task<int> task = ...;
Action<int> f = ...;
现在我想设置它,以便一旦任务完成并返回其整数结果,callfack
f
将使用该整数调用 - 不需要主线程等待任务完成:Task.ContinueWith
方法:task.ContinueWith(t => f(t.Result));
TaskAwaiter
对于任务,并使用其类似事件的界面:TaskAwaiter<int> awaiter = task.GetAwaiter();
awaiter.OnCompleted(() => f(awaiter.GetResult()));
现在,我意识到
TaskAwaiter
不打算在应用程序代码中普遍使用,主要由 await
内部使用。关键词。但是为了加深我对TPL的理解,我想知道:
解决方案(1)和(2)之间有什么实际区别吗?
例如,
最佳答案
一个区别是
task.ContinueWith(t => f(t.Result));
不会捕获当前的同步上下文,例如,在 UI 应用程序中 - 回调将在线程池线程上执行。尽管
TaskAwaiter<int> awaiter = task.GetAwaiter();
awaiter.OnCompleted(() => f(awaiter.GetResult()));
将捕获同步上下文,并在 UI 线程上执行回调。
当然你也可以用
ContinueWith
做同样的事情:task.ContinueWith(r => f(r.Result), TaskScheduler.FromCurrentSynchronizationContext());
但这不是你使用的问题。因此,您的问题中提供的方法至少在这方面有所不同。
异常表示也有区别,访问
Task.Result
如果任务出错将抛出 AggregateException
(有一个或多个异常作为内部异常),同时访问 awaiter.GetResult()
不会在 AggregateException
中包装抛出的异常并将按原样重新抛出它(并且如果有多个异常,例如来自 Task.WhenAll
- 除一个之外的所有异常都将被忽略,并且只会抛出一个)。
关于c# - 响应任务完成 : `.ContinueWith()` vs `GetAwaiter().OnCompleted()` ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49921297/