协程(coroutine)到底是啥

2021-05-31 21:48:09 +08:00
 zxCoder

想到我头都要炸了,还是没想明白

中文英文资料都搜了看了一些,就只是知道:

可是这明明很抽象。。。想不明白

一些语言里的 async 和 await 这种算协程吗,协程到底是个什么概念

2496 次点击
所在节点    问与答
14 条回复
ysc3839
2021-05-31 21:51:13 +08:00
你说的前两点应该描述的是有栈协程,async await 这种是无栈协程。

我没怎么了解过有栈协程。至于无栈协程,我是理解成“回调函数的语法糖”。
Jirajine
2021-05-31 21:52:06 +08:00
https://os.phil-opp.com/async-await/
看第一节语言无关的部分
Nitroethane
2021-05-31 22:17:51 +08:00
拿 Linux 平台上的 Go 来说明问题。
Linux 中并没有真正意义上的线程,而被叫做轻量级进程。内核源码注释中进程( process )、线程( thread )和任务( task )经常混用。
协程就是 Go 的 runtime 实现的**类似于**多线程的机制,协程的调度由 Go 的 runtime 中的协程调度器实现。当一个协程调用了阻塞操作(例如获取锁、读取的 channel 中没有数据等)时,runtime 的协程调度器会将此协程投入等待队列使其睡眠,然后调度其他处于运行队列的协程继续执行。当处于睡眠状态的协程所等待的事件发生后,调度器会唤醒并投入运行队列。
这个协程调度器是由用户态的程序 Go 自己实现的,跟内核的进程调度器完全没有关系。
ReferenceE
2021-05-31 22:39:09 +08:00
@ysc3839 async 和 await 是主要是面向 continuation 计算续集的,和协程不是一个东西
irytu
2021-05-31 23:04:47 +08:00
xv6 源码里读一读 swtch.S 文件里的汇编代码,一个简单的 x86 coroutine 实现
irytu
2021-05-31 23:05:23 +08:00
ysc3839
2021-05-31 23:09:17 +08:00
@ReferenceE 我不知道 stackless coroutine 在中文应该怎么翻译,但似乎大家都叫无栈协程,所以我也这么叫了。
ly841000
2021-05-31 23:24:17 +08:00
用户态调度的非抢占式轻量线程
zhangbohun
2021-05-31 23:44:21 +08:00
不完全严谨的解释,仅供参考:
线程是操作系统“调度”CPU 算力的最小单位,而所谓“调度”基本就是切换运行时的上下文数据(寄存器里的数据)然后根据 OS 的调度算法换着运行;而协程就是在更上层(比如各种语言的运行时或者工具库的实现)模拟这种暂存上下文数据并且自定义调度算法的轻量级“线程”;而 async 和 await 这个只是语法层面用于标记协程切换和调度的一种方案
GeruzoniAnsasu
2021-06-01 01:16:45 +08:00
coroutine 是一种无须借助操作系统提供的线程 /进程设施即可实现多任务的机制。

假设当前有两个 task,执行完全一样的代码 while(1) {print"1"}

显然由于没有线程,初始执行的那个 task 会一直执行下去,另一个 task 永远没机会执行。


但如果引入一个调度器和 [打断 /恢复] 的机制,就能够实现 task 间的切换,此时 task 代码类似这样

while(1) {print"1";yield}

yield 语句处将执行流跳到这个 task 外,比如调度器;这时候调度器就能将执行流转给另一个 task,另一个 task 从之前 yield 处恢复执行。

两个 task 不断执行 yield,不断交换执行权,就能让两个 task 的循环都可以同时进行下去,实现并发






协程需要主动让出执行权,而操作系统的线程借助时间中断可以在当前 task 的任何地方打断并切换,这是协程最典型的特征。不过一般出于写法一致性等理由,会把协程的主动交换点藏在一些不容易发现的地方,比如 await 、yield from 、coroutine.sleep 等,这些语句 /函数其实都是把执行权交到另一个协程( await )或调度器( sleep )上。

任意一个协程把执行权交给调度器后调度器发现某个协程的 sleep 已超时,它把执行权交回 sleep 的这个协程,从这个协程来看就会好像自己真的 sleep 了一样。执行权交给目标协程后目标协程完全结束并返回,把执行权交给上层 wait 中的协程(完全结束前只可能把执行权交给调度器或第三个协程),从 wait 协程来看就好像自己真的等到目标协程返回才继续一样。




stackful/stackless 只是实现 [打断 /恢复] 那个恢复机制的做法不同而已
Rwing
2021-06-01 08:31:58 +08:00
c# 的 async/await 和 js 的 async/await 应该不是一回事吧
bytesfold
2021-06-01 09:08:06 +08:00
建议读 《深入了解计算机系统》
wanguorui123
2021-06-01 09:35:22 +08:00
协程就是多线程的 NodeJS 事件队列
Mogamigawa
2021-07-20 14:50:09 +08:00
接受协程的角色设定就行了,大脑简单点不要太复杂。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/780458

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX