是一个Go goroutine是一个协程?

Sła*_*osz 52 multithreading go goroutine

在Google I/O 2012演示文稿Go Concurrency Patterns中,Rob Pike提到几个goroutine可以存在于一个线程中.这是否意味着它们是作为协同程序实现的?如果没有,它们是如何实施的?欢迎链接到源代码.

kos*_*tix 54

协同作用,IMO意味着支持将控制转移到另一个协程的明确手段.也就是说,程序员在确定何时协程应该暂停执行并将其控制权传递给另一个协程时(通过调用它或通过返回/退出(通常称为让步))来编程协程.

Go的"goroutines"是另一回事:它们隐含地放弃了某些不确定1的控制,当goroutine即将在I/O完成,频道发送等某些(外部)资源上休眠时发生这种情况.这种方法与通过频道共享状态相结合使程序员能够将程序逻辑编写为一组连续的轻量级进程,从而消除了基于协程和基于事件的方法所共有的意大利面条代码问题.

关于实现,我认为它们与(不幸的是不太知名的)"State Threads"库非常相似,只是相当低级别(因为Go不依赖于这样的libc事情并且直接与OS对话)内核) - 你可以阅读ST库的介绍性文章,其中概念得到了很好的解释.


1事实上,这些点比协程的点更不确定,但比抢占式多任务处理中的真实OS线程更具决定性,其中每个线程可能在任何给定时间点和线程控制流中被内核挂起.

  • @Alexey 我相信你混淆了决定论和合作。在抢占式多任务(线程)中,程序依赖操作系统来决定何时暂停并发运行的任务;在非抢占式(协作式)多任务处理中,程序定义如何拆分每个并发任务(协程)。在这两种情况下,都实现了并发;即,任务的完成顺序是动态的并且(通常)不可预测。 (2认同)

K Z*_*K Z 51

不完全的.Go FAQ部分为什么选择goroutines而不是线程?解释:

Goroutines是使并发易于使用的一部分.这个想法已经存在了一段时间,它将独立执行的函数 - 协程 - 复用到一组线程上.当协程阻塞时,例如通过调用阻塞系统调用,运行时自动将同一操作系统线程上的其他协同程序移动到另一个可运行的线程,这样它们就不会被阻塞.程序员没有看到这一点,这就是重点.结果,我们称之为goroutines,可以非常便宜:除非他们在长时间运行的系统调用中花费大量时间,否则它们的成本只比堆栈的内存多,这只是几千字节.

为了使堆栈变小,Go的运行时使用分段堆栈.一个新的goroutine给了几千字节,这几乎总是足够的.如果不是,则运行时自动分配(并释放)扩展段.开销平均每个函数调用大约三个便宜的指令.在同一地址空间中创建数十万个goroutine是切实可行的.如果goroutines只是线程,系统资源将以更小的数量运行.

  • 由于 v1.3 golang stack 从分段模型切换到连续模型。请参阅 Go 1.3 的 [发行说明](https://golang.org/doc/go1.3#stacks)。实际上,常见问题解答已相应更新:-) (2认同)

Vol*_*ker 5

goroutine 是适当的协程还是类似的东西经常在https://groups.google.com/forum/?fromgroups=#!forum/golang-nuts 上讨论。有些人可能会争论这些微妙之处,但对于大多数人来说:goroutine 是一个协程。

查看https://docs.google.com/document/d/1TTj4T2JO42uD5ID9e89oa0sLKhJYD0Y_kqxDv3I3XMw/edit 以了解调度程序的工作原理。


zan*_*ngw 5

Go 的每个协程作者:Russ Cox

简而言之

  • goroutine 创建一个新的并发、并行控制流
  • 协程创建一个新的并发、非并行控制流。

由于关于 goroutine 的答案有更多,这里有来自 Coroutines for Go的更多关于协程的详细信息

  • 协程提供了没有并行性的并发性:当一个协程正在运行时,恢复或让出它的那个协程就不会运行。对于编写需要并发进行程序结构但不需要并行性的程序来说,协程是一个有用的构建块
  • 由于协程一次运行一个并且仅在程序中的特定点切换,因此协程可以在彼此之间共享数据而无需竞争。显式开关充当同步点,创建发生在边缘之前。
  • 由于调度是显式的(没有任何抢占)并且完全无需操作系统即可完成,因此协程切换大约需要 10 纳秒,通常甚至更短。启动和拆卸也比线程便宜得多。
  • goroutine 切换接近几百纳秒,因为 Go 运行时承担了一些调度工作。然而,goroutine 仍然提供线程的完全并行性和抢占性。

为什么在 Go 中使用协程?

Go 中的协程提案旨在增强处理并发的方式。与强调并行性的 Goroutines 不同,Go 中的协程旨在促进并发,而不必调用并行性。这种方法在需要具有并发元素的结构化程序设计同时避免并行执行的复杂性和潜在陷阱的场景中特别有用。

Goroutine 与 Coroutine

  • 协程专注于在特定点产生并恢复执行,支持并发,但不支持并行。对于某些编程场景,受控执行流比同时任务处理更重要。
  • Go 中的 Goroutine 提供完全并行性和抢占性,运行时处理一些调度工作。它们可以同时并行地运行多个控制流。