sml*_*mls 5 c# continuations task task-parallel-library
假设我有一个Task生成的int,以及一个接受的回调int:
Task<int> task = ...;
Action<int> f = ...;
Run Code Online (Sandbox Code Playgroud)
现在,我想对其进行设置,以便一旦任务完成并返回其整数结果,f将使用该整数来调用callfack ,而无需主线程等待任务完成:
据我了解,典型的解决方案是Task.ContinueWith方法:
task.ContinueWith(t => f(t.Result));
Run Code Online (Sandbox Code Playgroud)但是,也可以TaskAwaiter为任务获取一个,并使用其类似事件的界面:
TaskAwaiter<int> awaiter = task.GetAwaiter();
awaiter.OnCompleted(() => f(awaiter.GetResult()));
Run Code Online (Sandbox Code Playgroud)现在,我意识到这TaskAwaiter并不是应用程序代码中的常用对象,主要存在于内部供await关键字使用。
但是,为了加深我对TPL的理解,我想知道:
解决方案(1)和(2)之间有什么实际区别?
例如,
一个区别是
task.ContinueWith(t => f(t.Result));
Run Code Online (Sandbox Code Playgroud)
不会捕获当前同步上下文,并且在 UI 应用程序中 - 回调将在线程池线程上执行。尽管
TaskAwaiter<int> awaiter = task.GetAwaiter();
awaiter.OnCompleted(() => f(awaiter.GetResult()));
Run Code Online (Sandbox Code Playgroud)
将捕获同步上下文,并且回调将在 UI 线程上执行。
当然你也可以这样做ContinueWith:
task.ContinueWith(r => f(r.Result), TaskScheduler.FromCurrentSynchronizationContext());
Run Code Online (Sandbox Code Playgroud)
但这不是您所使用的问题。因此,您的问题中提供的方式至少在这方面是不同的。
异常表示也存在差异,Task.Result如果任务发生故障,则访问将抛出AggregateException(一个或多个异常作为内部异常),而访问awaiter.GetResult()不会将抛出的异常包装起来AggregateException,并将按原样重新抛出(如果有多个异常,例如from Task.WhenAll- 除一个之外的所有内容都将被忽略,并且只有一个将被抛出)。