1

以下代码永远运行,而不是在开始后一秒钟停止。带有无限循环的 go 例程似乎阻止了另一个发送到超时通道。这正常吗?

 func main(){
   timeout:=make(chan int)
   go func(){
      time.SLeep(time.Second)
      timeout<-1
    }()

    res:=make(chan int)
    go func(){
        for{
        }
        res<-1
    }()
    select{
        case<-timeout:
            fmt.Println("timeout")
        case<-res:
            fmt.Println("res")
    }
}
4

2 回答 2

3

那是因为使用单个处理器,您的第二个 goroutine 将忙于等待(通过循环独占处理器并且永远不会让另一个 goroutine 运行)。

例如,如果您将 atime.Sleep(time.Millisecond)放在 for 循环中,它就会起作用:

http://play.golang.org/p/M4jeckcmov

于 2013-07-30T17:53:09.397 回答
3

简短的回答:是的。

当前的实现使用 goroutine 之间的协作调度。这意味着一个 goroutine 必须将执行移交给调度程序,以便另一个 goroutine 运行。将来有希望使用不会有此限制的抢占式调度程序。

当以下任何一种情况发生时,Goroutines 会屈服于调度程序(可能不是一个完整的列表):

  • 无缓冲 chan 发送/接收
  • 系统调用(包括文件/网络读取和写入)
  • 内存分配
  • time.Sleep() 被调用
  • runtime.Gosched() 被调用

最后一个允许您在处理器密集型循环时手动让步给调度程序。我从来没有发现需要它,因为我使用的几乎所有东西都有足够的通信(通道或系统 io),我的程序永远不会卡住。

还有 GOMAXPROCS 您可能会听到它作为解决方案。虽然它允许你所有的 goroutine 通过将它们放在不同的线程中运行,但垃圾收集器最终会尝试运行并停止世界。当它停止世界时,不允许运行任何 goroutine,如果高 cpu 的 goroutine 永远不会产生,GC 将永远阻塞 goroutine 但永远不会运行。

于 2013-07-30T17:57:10.000 回答