最近 go 的 GC 模块的开发者提出了一个提案,叫做“非协作式的 goroutine 抢占”:golang/proposal
这个提案要实现的,如字面意思,就是强行让一个 goroutine 让出 CPU,不管该 goroutine 在做什么,不需要 goroutine 的“协作”,就能抢占该 goroutine 的 CPU 时间。go 现在的调度器,如果想从外部让一个 goroutine 让出 CPU 时间,只能在函数的入口处做一些手脚,让该 goroutine 在调用函数之前,发现它应该让出 CPU,这就是协作式的,因为需要 goroutine 执行到那一个路径,外部只能等待它执行到那里,或者其他一些触发到调度的代码路径。
这个提案的方案是,直接用信号让执行 goroutine 的系统线程切换到信号处理器,从而实现 goroutine 的打断。以前为什么不能这样做呢?因为涉及到 GC。现在需要打断 goroutine 的原因,主要是 GC 过程需要暂停所有 goroutine,而 GC 过程中对 goroutine 的状态也有要求,就是 goroutine 必须处于“安全点”,这样 GC 模块才能准确地知道哪些对象可以回收哪些不行。在 goroutine 不处于安全点时就打断,现在的 GC 模块是没法正确工作的。提案里的方案是要实现“处处都是安全点”,这样就能随时打断 goroutine 而不影响 GC 的工作(当然也有一些时机是没法成为安全点的,提案里也有解法)。
所以说,goroutine 的很多设计,其实是和 go 语言本身、和 go 运行时本身密切关联的。为什么要用 goroutine 而不是直接用系统线程?因为 GC 需要暂停所有 goroutine 的运行(时间很短,微秒以下),如果将这个交给操作系统来做,可能暂停需要等待的时间,就不太可控了,毕竟操作系统调度的时间片粒度是相对更粗的。另外还有开销的问题,使得直接使用系统线程,不如使用 goroutine。
另外也可以得出一个结论,goroutine 并不是一个简单的“协程”方案。goroutine 可以主动让出 CPU,也可以从外部强行让 goroutine 让出 CPU。这就不能叫做“协作式调度”了,自然也就不是“协程”。
所以拿 C++ 实现的各类协程,来和 goroutine 比较,是不适合的,特性都不一样。
本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度,google,bing,sogou 等
© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有