type
status
date
slug
summary
tags
category
icon
password
Property
Aug 9, 2024 11:59 AM
异步函数
async和await关键字可以让你写出和同步代码一样简洁且结构相同的异步代码
awaiting
await关键字简化了附加continuation的过程
其结构如下
它的作用相当于
async 修饰符
async修饰符会让编译器把await当做关键字而不是标识符(C#5以前可能会使用await作为标识符)
async修饰符只能应用于方法(包括lambda表达式)
该方法可以返回void,Task,Task<TResult>
async修饰符对方法的签名或public元数据没有影响(和unsafe一样),他只会影响方法内部
在接口内使用async时没有意义的
使用async来重载非async的方法确实合法的(只要方法签名一致)
使用了async修饰符的方法就是异步函数
异步方法如何执行
遇到await表达式,执行(正常情况下)会返回调用者
就像iterator里面的yield return
在返回前,运行时恢复加一个continuation到await 的task
为保证task结束时,执行会调回原方法,从停止的地方继续执行
如果发生故障,name异常会被重新抛出
如果一切正常,name它的返回值就会付给await表达式
可以await什么
你await的表达式通常是一个task
也可以满足下列的任意对象
有GetAwaiter方法,它返回一个awaiter(实现了INotifyCompletion.OnCompleted接口)
返回适当类型的GetResult方法
一个bool类型的IsCompleted属性
捕获本地状态
await表达式的最牛指出就是它几乎可以出现在任何地方
特别的,在一部方法内,await表达式可以替换任何表达式
除了lock表达式和unsafe上下文
await之后在哪个线程上执行
在await表达式之后,编译器依赖于continuation(通过awaiter模式)来继续执行
如果在复客户端应用的UI线程上,同步上下文会保证后续是在原线程上执行
构造,就会在task结束的线程上继续执行
UI上的await
本例中,只有GetPrimesCountAsync中的代码是在worker线程上运行
Go中的代码会租用UI线程上的时间
可以说:Go是在消息循环中“伪并发”的执行
也就是说:它和UI线程处理的其他事件时穿插执行的
因为这种伪并发,唯一能发生“抢占”的时刻就是在await期间
这其实简化了线程安全,防止重新进入即可
这种并发发生在调用栈较浅的地方(Task.Run调用的代码里)
为了从该模型获益,真正的并发代码要避免访问共享状态或UI控件
与处理度的并发相比
例如使用BackgroundWorker
整个同步调用图都在worker线程上
必须在代码中到处使用Dispatcher.BeginInvoke
循环本身在worker线程上
引入了race condition
若实现取消和过程报告,会使得线程安全问题会容易发生,在方法中新添加任何的代码也是同样的效果
- 作者:Kitety
- 链接:https://www.kitety.com/article/c-sharp-async-await
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章