我想知道实现的原因:
package main func main() { c := make(chan struct{}) go func() { print("a") for { } }() go func() { print("b") for { } }() go func() { print("c") c <- struct{}{} for { } }() <-c } ❯❯❯ GOMAXPROCS=2 go run sample1.go ab <--- blocks.
package main // static void loop() { for(;;); } import "C" func main() { c := make(chan struct{}) go func() { print("a") C.loop() print("x") }() go func() { print("b") C.loop() print("y") }() go func() { print("c") c <- struct{}{} C.loop() print("z") }() <-c } ❯❯❯ GOMAXPROCS=2 go run sample2.go abc <--- ends gracefully.
更具体地说,我的意思是C紧密循环与go例程调度中的Go循环有何不同。即使应该在Go程序结束时突然终止C紧密循环,我还是想知道依靠这种行为来启动C任务而不阻塞Go程序是否安全。
运行时无法抢占真正的繁忙循环。没有调度点的CPU密集型循环必须位于其自己的线程中,其他goroutine才能运行。函数调用和通道发送或接收操作都产生。网络IO是异步调度的,文件IO具有其自己的线程。
通常设置GOMAXPROCS> 1就足够了,但是由于您有3个这样的循环,并且只有2个线程,因此调度程序仍然被阻塞。如果您有一个有效的CPU密集型循环,难以安排goroutine,则可以runtime.GoSched()定期调用以让出给调度程序。在现实世界中,唯一通常会发生这种情况的地方是编程错误,即您有一个空循环。
GOMAXPROCS
runtime.GoSched()
所有cgo调用都在go运行时之外的它们自己的线程中发生,因此这些循环除了浪费CPU外,对主循环没有任何影响。