在 Google I/O 2012演示文稿 Go 并发模式中,Rob Pike 提到几个 舞蹈可以存在于一个线程中。这是否意味着它们是作为 协同动作实现的?如果没有,它们是如何实施的?欢迎链接到源代码。
Goroutine 是一个独立的执行“线程”。这是国际海事组织没有真正可比拟的协同程序。在第一种近似情况下,goroutines 可以由 真的操作系统线程实现。AFAIK,这是 gccgo 的早期版本的情况。另一个区别是 goroutine 可能会被抢占。
当前 Go 编译器将 goroutine 实现为非常轻量级的用户空间“线程”。有一个明显的特点。绿线是可以切换到不同操作系统线程的 goroutines。
我想你可以在这里找到一些相关的兴趣点: Proc
一个 goroutine 是否是一个正确的协同程序或只是类似的东西经常被讨论在 https://groups.google.com/forum/?fromgroups=#!forum/golang-nuts。有些人可能会争论这些微妙之处,但是对于大多数人来说: goroutine 是一个协同程序。
看看这个 https://docs.google.com/document/d/1ttj4t2jo42ud5id9e89oa0slkhjyd0y_kqxdv3i3xmw/edit 了解调度程序的工作原理。
一个协同程序意味着支持 露骨手段将控制权转移到另一个协同程序。也就是说,当程序员决定协程何时应该暂停执行并将其控制传递给另一个协程(通过调用它或通过返回/退出(通常称为屈服))时,他们以某种方式编写协程。
Go 的“ goroutines”是另一回事: 它们在某些 不确定点交出控制权。 1点发生在 Goroutine 即将睡眠于某些(外部)资源(如 I/O 完成、通道发送等)时。这种方法与通过通道共享状态相结合,使程序员能够将程序逻辑编写为一组 顺序轻量级进程,从而消除了协程和基于事件的方法中常见的意大利面条式代码问题。
关于实现,我认为它们与 “状态线程”库非常相似(不幸的是,它们并不太知名) ,只是级别比较低(因为 Go 并不依赖于 libc或类似的东西,而是直接与操作系统内核对话)ーー你可以阅读 ST 库的介绍性文章,其中对这个概念进行了很好的解释。
libc
事实上,这些点比协程的确定性要低,但比 先发制人的多任务处理下真正的 OS 线程更确定,在 先发制人的多任务处理下,每个线程可能在任何给定的时间点和线程控制流中被内核挂起。 2021-05-28更新: 实际上,自从 Go 1.14,Goroutines (几乎)是先发制人地调度的。 但是应该注意的是,它仍然不是典型的内核对它管理的线程的 那个硬核抢占,但是它比以前更加接近; 至少现在 Goroutine 不可能在进入繁忙的循环后变得不可抢占。
不完全是这样。《 Go 常见问题解答》的 为什么用 goroutines 代替线程章节解释道:
Goroutines 是使并发易于使用的一部分。这个想法已经存在了一段时间,就是将独立执行的函数(协程)多路复用到一组线程上。当协程阻塞时,比如通过调用阻塞系统调用,运行时会自动将同一操作系统线程上的其他协程移动到不同的、可运行的线程,这样它们就不会被阻塞。程序员看不到这些,这才是重点。结果,我们称之为 goroutines,可以非常便宜: 它们只有很少的堆栈内存开销,只有几千字节。 为了使堆栈变小,Go 的运行时使用可调整大小的有界堆栈。一个新生成的 goroutine 被赋予几千字节,这几乎总是足够的。如果不是这样,运行时将增加(并收缩)用于自动存储堆栈的内存,允许许多 goroutine 存在于适度的内存中。每个函数调用的 CPU 开销平均约为三条廉价指令。在同一个地址空间中创建数十万个 goroutine 是切实可行的。如果 goroutine 仅仅是线程,那么系统资源将以更小的数量耗尽。
Goroutines 是使并发易于使用的一部分。这个想法已经存在了一段时间,就是将独立执行的函数(协程)多路复用到一组线程上。当协程阻塞时,比如通过调用阻塞系统调用,运行时会自动将同一操作系统线程上的其他协程移动到不同的、可运行的线程,这样它们就不会被阻塞。程序员看不到这些,这才是重点。结果,我们称之为 goroutines,可以非常便宜: 它们只有很少的堆栈内存开销,只有几千字节。
为了使堆栈变小,Go 的运行时使用可调整大小的有界堆栈。一个新生成的 goroutine 被赋予几千字节,这几乎总是足够的。如果不是这样,运行时将增加(并收缩)用于自动存储堆栈的内存,允许许多 goroutine 存在于适度的内存中。每个函数调用的 CPU 开销平均约为三条廉价指令。在同一个地址空间中创建数十万个 goroutine 是切实可行的。如果 goroutine 仅仅是线程,那么系统资源将以更小的数量耗尽。