type
status
date
slug
summary
tags
category
icon
password
Property
Sep 20, 2023 03:17 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控件
notion image
notion image

与处理度的并发相比

例如使用BackgroundWorker
整个同步调用图都在worker线程上
必须在代码中到处使用Dispatcher.BeginInvoke
循环本身在worker线程上
引入了race condition
若实现取消和过程报告,会使得线程安全问题会容易发生,在方法中新添加任何的代码也是同样的效果
C#异步编程-18 异步和 continuation 以及语言的支持C#异步编程-20 编写异步函数
  • Waline
Kitety
Kitety
独特为佳
公告
我曾经七次鄙视自己的灵魂
--卡里·纪伯伦
第一次,当它本可进取时,却故作谦卑;
第二次,当它在空虚时,用爱欲来填充;
第三次,在困难和容易之间,它选择了容易;
第四次,它犯了错,却借由别人也会犯错来宽慰自己;
第五次,它自由软弱,却把它认为是生命的坚韧;
第六次,当它鄙夷一张丑恶的嘴脸时,却不知那正是自己面具中的一副;
第七次,它侧身于生活的污泥中,虽不甘心,却又畏首畏尾。
 
最新评论
Loading...