2013-07-30 65 views
0

下面的代码永远运行,而不是在开始后停止一秒。 带有无限循环的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") 
    } 
} 
+0

这SO Q/A答案 http://stackoverflow.com/questions/12413510/why-is-this-go-code-blocking?rq=1 对不起那个。 – JulienFr

回答

2

简短的回答:是的。

当前的实现使用协同调度。这意味着goroutine必须将执行权交给调度程序,以便另一个goroutine运行。未来有希望使用不具有此限制的抢先式调度程序。

够程产量到调度时任何会出现以下情况(可能不是一个完整的列表):

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

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

还有GOMAXPROCS,你可能会听到这个解决方案。虽然它可以让你的所有goroutines通过将它们放入不同的线程来运行,但垃圾收集器最终会尝试运行并停止这个世界。当它停止世界时,不允许任何套间运行,并且如果高cpu套间从不放弃,GC将永远阻止套间,但从不运行。

+0

只是好奇:如何在没有操作系统支持的情况下实施抢先式调度程序(因此没有操作系统线程)?那么,我认为它可能*有可能在自定义虚拟机中实现某种先发制人的多任务处理,但它可能应该只是解释,因此非常缓慢。对Go来说这显然是不可行的。 –

+0

由此判断:https://groups.google.com/forum/#!searchin/golang-dev/pre-emptive/golang-dev/vtrWpvf8nMA/PPs5Eqpk-VgJ它看起来像计划成为监视器操作系统线程处理它。 – LinearZoetrope

+0

如果你知道调度程序是合作的(我们这么做),那么确保程序合作并不困难。这对运行时实现者来说是一个相当大的好处,因为先占调度通常效率较低,因为需要保存的上下文无法优化。 Transputer遵循合作原则,实现了令人难以置信的快速上下文切换时间(类似于过程调用开销)......现代Occam-Pi编译器(来自Kent)也是如此。 –

2

这是因为带有单处理器,你的第二个够程会忙等待(由循环和从来没有让其他的goroutine运行独占处理器)。

它的工作原理,如果你把,例如time.Sleep(time.Millisecond)里面的for循环:

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

+0

Thx Puerkito。有一个很长的答案[here](http://stackoverflow.com/questions/12413510/why-is-this-go-code-blocking) – JulienFr