为什么这是Go代码阻塞?
我编写了以下程序:为什么这是Go代码阻塞?,go,goroutine,Go,Goroutine,我编写了以下程序: package main import ( "fmt" ) func processevents(list chan func()) { for { //a := <-list //a() } } func test() { fmt.Println("Ho!") } func main() { eventlist := make(chan func(), 100) go proc
package main
import (
"fmt"
)
func processevents(list chan func()) {
for {
//a := <-list
//a()
}
}
func test() {
fmt.Println("Ho!")
}
func main() {
eventlist := make(chan func(), 100)
go processevents(eventlist)
for {
eventlist <- test
fmt.Println("Hey!")
}
}
主程序包
进口(
“fmt”
)
func processevents(list chan func()){
为了{
//a:=更新(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,从而导致您观察到的结果:您实际上创建了死锁t计划程序无法检测到hat或将其破坏
Go中通常不需要空循环,在大多数情况下,空循环表示程序中存在错误。如果出于任何原因需要空循环,则必须在每次迭代中通过调用runtime.Gosched()
手动向调度程序屈服
for {
runtime.Gosched()
}
将GOMAXPROCS
设置为值>1
是一种解决方案。虽然这将消除您观察到的直接问题,但如果计划程序决定将循环goroutine移动到自己的操作系统线程(即),它将有效地将问题移动到另一个操作系统线程。除非您调用runtime.LockOSThread()
在processevents
函数的开头。即使如此,我仍然不会依赖此方法作为一个好的解决方案。只需调用runtime.Gosched()
在循环本身中,将解决所有问题,无论goroutine在哪个操作系统线程中运行。这里是另一个解决方案-使用范围
从通道读取。此代码将正确地向调度程序屈服,并在通道关闭时正确终止
func processevents(list chan func()) {
for a := range list{
a()
}
}
好消息是,自Go 1.2(2013年12月)以来,原来的程序现在按预期运行。
你可以
“调度程序中的抢占”一节对此进行了解释:
在以前的版本中,一个永远循环的goroutine可能会饿死
在同一线程上执行其他goroutine,当
GOMAXPROCS只提供了一个用户线程
addressed(已寻址):调度程序偶尔在进入
功能
因此,GOMAXPROCS设置为1作为默认值?您声明“从Go 1.2开始,调度程序按照先发制人的多任务处理原则工作。这意味着原始问题中的问题(以及下面介绍的解决方案)是对我来说,这似乎不是真的。因为循环仍然从不调用非内联函数。在游乐场上,程序以“[进程花费的时间太长]程序退出”结束