Coroutine,以及中文的「协程」,是与 thread(线程)相对应的一个词。
线程是抢占式的(preemptive),它是基于 OS 将 CPU 资源切分成时间片,在每个时间片内选择一个线程来运行。时间片一到,运行权被 OS 回收,重新调度。
Coroutine 的意思是 cooperative function。它与线程类似的地方在于,它也有调用栈和局部变量,也可以使用全局变量。但是它不是抢占式的。一个协程通过 yield 让出其控制权,使得调度器(编程语言所实现,而不是 OS 所实现)可以将运行权交给另外一个协程。
当然运行协程的仍然是线程。只是从编程模型上看,使用协程来做协作的粒度更小。编程语言的协程实现中,可以用一个或者多个线程来实现整套调度和运行。
协程的好处:
- 实现了 async / await 模型(可能不够准确),使得 可以用同步方式写异步代码
- 非常轻量,没有线程那么重的 context switching 和内存消耗
- 减少了对锁的需要,增加了系统资源利用率
中文语境中的「协程」,稍微有一些需要注意的点:
- 对于 Python 及 Lua,协程的含义和实现与上文描述一致
- 对于 Go,其「协程」名为 goroutine,并不是真正的 “协” 程,因为它是抢占式的
对称与非对称性
Coroutine 的实现有两种:
- 非对称的(asymmetric):也称半对称的(semi-symmetric),表示协程实现的 API 中,即有调用协程的 API,也有 将控制权交还给调用者的 API(比如 Python 及 Lua 的
yield
)。这种实现中,这两个协程的关系像是普通函数一样,有调用方和被调方 - 对称的(symmetric):这种实现中 没有 将控制权交还给调用者的 API。协程间没有调用关系。没有用过这种实现的协程,感觉缺少方便性。
参考: