关于 绿色线程(Green Thread) 和 协程(Coroutine) 的一点思考
引子
这个话题起源于今天在某不存在的聊天软件 Telegram 上有位网友提问了一个问题:“ Green Thread
和 Coroutine
的区别在哪里?”
因为我的擅长语言是 C++ 的原因,一开始连Green Thread
是什么都不知道。
查询了许多资料(中文网站)后发现许多搜索结果描述 Green Thread
和 Coroutine
是同一种东西——我几乎相信了,如果不是维基给了两个不同的页面介绍这两者的话。
更换英文搜索后我得到了更详细的资料(在文末列出),证明 Green Thread
和 Coroutine
是不同的东西。我把这些记录在本文,希望能对读者有所启发。
正文
首先来介绍一下 Green Thread
和 Coroutine
:
绿色线程 Green Thread
绿色线程 Green Thread
的概念是相对于操作系统线程(原生线程 native thread
)提出的,因为绿色线程并不是操作系统级别的概念。
绿色线程实际上是语言级别实现的线程。通常由 VM 来进行控制其资源分配和调度。因此,当一个绿色线程使用系统调用被阻塞时,操作系统并不会帮助调度其他线程,因此会导致该进程内所有线程(绿色线程)被阻塞。
第一个提出绿色线程概念的是早期 Java 的线程库,因为本身与系统无关的特性,可以在没有原生线程支持的环境中运行。
协程 Coroutine
协程也是在用户层(语言级别)进行实现的,是一种比线程更小的执行单元。协程自带 CPU 上下文,因此可以在任意时刻切换到别的协程。和线程比起来,协程的切换不需要操作系统进行保存和恢复CPU 上下文,自己的缓存数据等,因为所有的协程都存在于同一个线程之中,所以协程的切换只有单纯的 CPU 上下文切换,开销很小。
协程也有一个调度器,但是是被动调度的,也就是说,只有当前运行的协程主动的让出 CPU,调度器才会从协程池中调用下一个协程。这也是协程和上边几种最大的区别:协程的调度方式是合作式(Cooperative
),也可以叫做非抢占式(Non-Preemptive
);而上边三种都是抢占式调度(Preemptive
)。
两者的比较
这里来列出 绿色线程
和 协程
的共同点:
- 都是用户态操作。
- 都会被 I/O 操作堵塞当前
原生线程 native thread
。 - 开销都比较小(大概)
之后自然是列出不同点:
- 上下文不同
- 协程大多数实现中不保存完整的上下文,比如我知道的腾讯 C++ 协程库 libco 就选择了丢弃浮点运算的操作(他们可能想着服务器环境不怎么需要浮点运算)
并且内联汇编加快上下文切换速度导致只能支持 X86(离题)。所以协程的开销尤其小。 - 绿色线程保存完整的上下文,一般都由虚拟机实现(大部分),开销比较大。
- 协程大多数实现中不保存完整的上下文,比如我知道的腾讯 C++ 协程库 libco 就选择了丢弃浮点运算的操作(他们可能想着服务器环境不怎么需要浮点运算)
- 并行性不同
- 一个原生线程开出多个协程,这些协程彼此并不能并行,只能并发。并发与并行的简单解释
- 绿色线程这边比较复杂。要分情况讨论:
- 在早期 JAVA 使用绿色线程的时候,所有的绿色线程都是属于同一个线程的,并没有利用到 CPU 的多核处理程序。这时候绿色线程也是只能并发不能并行的。
- 在现在的绿色线程实现中,绿色线程会被匹配到一个原生线程池,从原生线程池中获取原生线程来执行绿色线程。有时候是 1 个原生线程执行 m 个绿色线程——这时候和早期没什么区别;有时候是 n 个原生线程执行 m 个绿色线程——这时候的绿色线程就获得了并行能力。
由最重要的并行性比较中可以看出,绿色线程和协程差别还是挺大的。在目前流行的编程语言中,有的语言选择了协程,有的语言选择了绿色线程,我用的 C++ 似乎没有绿色线程可以用的样子。
参考资料
正经的参考资料:
- Processes, threads, green threads, protothreads, fibers, coroutines: what's the difference?
- 协程 - 维基百科
- 绿色线程 - 维基百科
- 协程?还有纤程、绿色线程、线程、进程??
- Java的Green threads是Coroutine吗?
说绿色线程等于协程的文章(找不到原始出处了):
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。