go程阻塞其他一个。

huangapple go评论83阅读模式
英文:

go routine blocking the others one

问题

以下是翻译好的部分:

以下代码在开始后一秒钟后不会停止,而是一直运行。
具有无限循环的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")
    }
}
英文:

The following code run forever instead of stopping one second after the beginning.
The go routine with the infinite loop seems to prevent the other one from sending to the timeout channel. Is that normal ?

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

    res:=make(chan int)
    go func(){
        for{
        }
        res&lt;-1
    }()
    select{
        case&lt;-timeout:
            fmt.Println(&quot;timeout&quot;)
        case&lt;-res:
            fmt.Println(&quot;res&quot;)
    }
}

答案1

得分: 3

这是因为使用单个处理器,你的第二个goroutine会忙等待(通过循环来独占处理器,从而不让其他goroutine运行)。

如果在for循环中加入time.Sleep(time.Millisecond),它就能正常工作:

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

英文:

That's because with a single processor, your second goroutine will busy-wait (monopolize the processor by looping and never letting the other goroutine run).

It works if you put, for example, a time.Sleep(time.Millisecond) inside the for loop:

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

答案2

得分: 3

简短回答:是的。

当前的实现使用协作调度来管理goroutine。这意味着一个goroutine必须将执行权交给调度器,以便让另一个goroutine运行。未来有希望使用抢占式调度器来解决这个限制。

当发生以下情况时,goroutine会让出执行权给调度器(可能不是全面的列表):

  • 无缓冲通道的发送/接收操作
  • 系统调用(包括文件/网络读写)
  • 内存分配
  • 调用time.Sleep()
  • 调用runtime.Gosched()

最后一个允许你在有非常处理器密集型的循环时手动让出执行权给调度器。我从来没有发现过需要使用它的情况,因为我使用的几乎所有东西都有足够的通信(通道或系统IO),所以我的程序从来不会被卡住。

还有一个解决方案是使用GOMAXPROCS。虽然它可以通过将goroutine放在不同的线程中让它们都运行,但垃圾回收器最终会尝试运行并停止整个世界。当它停止整个世界时,没有goroutine被允许运行,如果高CPU的goroutine从不让出执行权,垃圾回收器将永远阻塞goroutine但永远不会运行。

英文:

Short answer: yes.

The current implementation uses cooperative scheduling among goroutines. This means that a goroutine must hand off execution to the scheduler for another goroutine to run. There is hope in the future to use a preemptive scheduler which will not have this limitation.

Goroutines yield to the scheduler when any of the following happens (may not be a comprehensive list):

  • unbuffered chan send/recv
  • syscalls (includes file/network reads and writes)
  • memory allocation
  • time.Sleep() is called
  • runtime.Gosched() is called

The last one allows you to manually yield to the scheduler when you have a very processor intensive loop. I have never found a need for it because just about everything I use has enough communication (channels or system io) that my programs never get stuck.

There is also GOMAXPROCS which you will probably hear as a solution to this. While it would allow all your goroutines to run by putting them in different threads, the garbage collector would eventually try to run and stop the world. When it stops the world, no goroutines are allowed to run and if the high cpu goroutines never yield, the GC will block goroutines forever but never run.

huangapple
  • 本文由 发表于 2013年7月31日 01:13:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/17953269.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定