type
status
date
slug
summary
tags
category
icon
password
Property
Aug 9, 2024 11:59 AM
Coninuation
一个Coninuation会对Task说:“当你结束的时候,继续再做点其他的事”
Coninuation通常是通过回调的方式实现的
- 当操作一结束,就开始执行
例子(prime)
在task上调用GetAwaiter会返回一个阿waiter对象
- 它的onCompleted方法会告诉之前的task:“当你结束/发生故障的时候要执行委托”
可以将Continuation附加到已经结束的task上面,此时Continuation将会被安排立即执行。
awaiter
任何可以暴露下列两个方法和一个属性的对象就是awaiter
- OnCompleted
- GetResult
- 一个叫做IsCompleted的bool属性
没有接口或者父类来统一这些成员
其中OnCompleted是INotifyCompletion的一部分
如果发生故障
如果之前的任务发生故障,那么当Continuation代码调用awaiter.GetResult()的时候,异常会被重新抛出
无需调用GetResult,我们可以直接访问task的Result属性
但是调用GetResult的好处是,如果task发生故障,那么异常会被直接的抛出,而不是包裹在AggregateException里面,这样的话catch块就简洁多了
非泛型task
针对非泛型的task,GetResult()方法有一个void的返回值,他就是用来重新抛出异常的
同步上下文
如果同步上下文出现了,那么OnCompleted会自动捕获它。并将Continuation提交到这个的上下文中。这一点在富客户端非常有用,因为他会把Continuation放回到UI线程中。
如果是编写一个库,则不希望上述的行为出现,因为开销较大的UI线程切换应该在程序运行离开库的时候只发生一次,而不是出现在方法调用之间。所以,我们使用ConfigureAwait方法来避免这种行为
如果没有同步上下文出现,或者你使用的是ConfigureAwait(false),那么Continuation会运行在前task的同一个线程上,从而避免不惜要的开销
ContinueWith
另外一种附加Continuation的方式就是调用task的ContinueWith方法
ContinueWith本身返回一个task,他可以用来附加更多的Continuation
但是,必须直接处理AggregateException
- 如果task发生故障,需要写额外的代码来把Continuation封装(marshal)到UI应用上
- 在非UI上下文中,若想让Continuation和task执行在同一个线程上,必须制定TaskContinuationOptions.ExecuteSynchronously,否则它将弹回线程池
Continuation对于并行编程来说非常有用
- 作者:Kitety
- 链接:https://www.kitety.com/article/c-sharp-async-task-continuation
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章