
从Go 1.2开始,调度程序基于 抢先式多任务处理 原则。这意味着原始问题(以及下面提供的解决方案)中的问题不再相关。
从Go 1.2发行说明中
简短答案调度程序中的抢占
在以前的版本中,永远循环的goroutine可能会使同一线程上的其他goroutine饿死,当GOMAXPROCS仅提供一个用户线程时,这是一个严重的问题。在Go>
1.2中,部分解决了此问题:调度程序在输入函数时偶尔被调用。这意味着任何包含(非内联的)函数调用的循环都可以被抢占,从而允许其他goroutine在同一线程上运行。
它不会阻止写入。它卡在的无限循环中
processevents。此循环永远不会屈服于调度程序,从而导致所有goroutine无限期锁定。
如果将对的调用注释掉
processevents,您将得到预期的结果,直到第100次写入为止。此时程序会出现紧急情况,因为没有人从该通道读取数据。
另一种解决方案是
runtime.Gosched()在循环中调用。长答案
使用Go1.0.2,Go的调度程序可以基于协作多任务处理原理工作。这意味着,通过在特定条件下使这些例程与调度程序交互,它将CPU时间分配给给定OS线程中运行的各种goroutine。当在goroutine中执行某些类型的代码时,就会发生这些“交互”。在go的情况下,这涉及进行某种I
/ O,系统调用或内存分配(在某些情况下)。
在空循环的情况下,永远不会遇到这种情况。因此,只要循环正在运行,就永远不允许调度程序运行其调度算法。因此,这可以防止它将CPU时间分配给其他等待运行的goroutine,从而导致观察到的结果:有效地创建了一个死锁,调度程序无法检测到该死锁。
空循环通常在Go中是不需要的,并且在大多数情况下,它将指示程序中的错误。如果出于某种原因确实需要它,则必须通过调用
runtime.Gosched()每次迭代来手动让出给调度程序。
for { runtime.Gosched()}提到
GOMAXPROCS将值设置
>1为解决方案。尽管这可以消除您所观察到的直接问题,但是如果调度程序决定将循环goroutine移动到自己的OS线程,则可以将问题有效地转移到其他OS线程。除非您
runtime.LockOSThread()在
processevents函数的开头进行调用,否则无法保证。即使那样,我仍然不会依靠这种方法来解决问题。只需调用
runtime.Gosched()循环本身,就可以解决所有问题,而不管goroutine在哪个OS线程中运行。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)