绿色线程
在计算机程序设计中,绿色线程是一种由运行环境或虚拟机调度,而不是由本地底层操作系统调度的线程。绿色线程并不依赖底层的系统功能,模拟实现了多线程的运行,这种线程的管理调配发生在用户空间而不是内核空间,所以它们可以在没有原生线程支持的环境中工作。
性能
在多核处理器上,原生线程可以自动将工作分配给多个处理器,而绿色线程做不到这一点。在某些虚拟机中,绿色线程可以启动得更快。然而,在单处理器计算机上,最有效的工作方式依旧没有定论。在一台运行着(过时很久的)Linux 2.2 内核的电脑上的测试表明:
- 绿色线程的性能在线程激活和同步上明显好于原生线程。
- Linux原生线程的性能在 I/O 操作和上下文切换 (Context Switch) 上略好于绿色线程。
当一个绿色线程执行一个阻塞的系统调用,不仅是当前的线程被阻塞,而是当前进程中的所有线程都会被阻塞。如果虚拟机在实现绿色线程时,为每个 I/O 操作分配特定的 I/O进程(这些进程对用户透明)可以减少用户编程时的负责度,但是为了避免阻塞问题,绿色线程必须使用异步I/O操作。
对应的,在使用原生线程时,也有方法可以减少线程激活和同步的开销:
- 使用线程池可以通过重用有限数量的线程来降低重新生成新线程的成本。
- 使用虚拟机和原生线程的语言可以使用Escape analysis来避免在不需要的情况下同步代码块。
Java虚拟机中的绿色线程
在Java 1.1中,绿色线程(至少在 Solaris 上)是JVM 中使用的唯一一种线程模型。由于绿色线程和原生线程比起来在使用时有一些限制,随后的 Java 版本中放弃了绿色线程,转而使用原生线程。Squawk虚拟机是一个例外,它是低功耗设备的操作系统和Java虚拟机的混合体。它使用绿色线程来保持机器语言的绝对最小并支持分离的迁移。Kilim和Quasar 是在随后的 JVM 版本中通过修改Java 编译器产生的字节码来实现绿色线程的开源项目(Quasar 也支持 Kotlin 和 Clojure)。
其他语言的绿色线程
还有一些其他的编程语言也实现了可以替代原生线程的绿色线程。例如:
- CHICKEN Scheme uses lightweight user-level threads based on first-class continuations[1]
- Common Lisp[2]
- CPython with greenlet, eventlet (页面存档备份,存于) and gevent (页面存档备份,存于), PyPy[3]
- D offers fibers, used for asynchronous I/O as the basis for tasks in the web framework Vibe.d
- Erlang
- Go[4]
- Haskell[4]
- Julia uses green threads for its Tasks (页面存档备份,存于).
- Limbo
- Lua uses coroutines (页面存档备份,存于) for concurrency. Lua 5.2 also offers true C coroutine semantics through the functions lua_yieldk (页面存档备份,存于), lua_callk (页面存档备份,存于), and lua_pcallk (页面存档备份,存于). The CoCo (页面存档备份,存于) extension allows true C coroutine semantics for Lua 5.1.
- Occam, which prefers the term "process" instead of "thread" due to its origins in communicating sequential processes
- Ruby before version 1.9[5]
- Racket (native threads are also available through Places[6])
- Rust support for green-threads is possible using mioco library
- SML/NJ's implementation of Concurrent ML
- Smalltalk (most dialects: Squeak, VisualWorks, GNU Smalltalk, etc.)
- Stackless Python supports either preemptive multitasking or cooperative multitasking through microthreads (so-called tasklets).[7]
- Tcl has coroutines (页面存档备份,存于) and an event loop[8]
- PHP supports green threads through coroutines (页面存档备份,存于)
Erlang 虚拟机中有一种有时候会被称为『绿色线程』的东西,但是和我们讨论的绿色线程有显著地差异,将他称为“绿色进程”可能更为合适。他们就像操作系统的进程(不像线程会共享系统资源),但在 Erlang 中是在 Erlang 运行系统(erts)中实现的。对与GHC Haskell,上下文切换发生在可配置的超时之后的第一次分配。 GHC线程也可能在其生命周期内的一个或多个OS线程上运行(GHC线程和OS线程之间存在多对多关系),允许在对称多处理机器上实现并行性,而不会创建比成本更高的操作系统线程 需要在可用数量的内核上运行。Occam 在这个列表中是不寻常的,因为它的原始实现与 Transputer 绑定,因此不需要虚拟机。 后来在移植到其他处理器时引入了一个仿照Transputer设计的虚拟机,这是一个有效的选择,因为涉及的开销很小。大多数 Smalltalk虚拟机不对评估步骤进行计数,但是VM仍然可以抢占外部信号上的执行线程(例如即将到期的定时器或即将可用的I/O)。通常使用循環制轮转调度机制,以便定期唤醒的高优先级进程来实现有效的分时分时抢占:
[
[(Delay forMilliseconds: 50) wait] repeat
] forkAt: Processor highIOPriority
其他实现方式,例如 QKS Smalltalk,总是采用分时的方式。 与大多数绿色线程实现不同,QKS Smalltalk也支持防止优先级反转。
参考资料
- . [5 November 2017]. (原始内容存档于2020-12-23).
- . GitHub. [2016-04-08]. (原始内容存档于2020-11-12).
- . [6 December 2015]. (原始内容存档于2020-06-04).
- . research!rsc. [2017-01-14]. (原始内容存档于2020-11-12).
for example both Go and Haskell need some kind of “green threads”, so there are more shared runtime challenges than you might expect
- . [22 August 2016]. (原始内容存档于2019-02-02).
- . [2011-10-13]. (原始内容存档于2021-04-13).
Places enable the development of parallel programs that take advantage of machines with multiple processors, cores, or hardware threads. A place is a parallel task that is effectively a separate instance of the Racket virtual machine.
- . [2008-08-27]. (原始内容存档于2013-02-06).
A round robin scheduler is built in. It can be used to schedule tasklets either cooperatively or preemptively.
- . [6 December 2015]. (原始内容存档于2018-10-11).