我有一个非常简单算法的研究计划.当成功来临时,goroutine应该通过os.Exit(0)关闭(结束).我等了一天,两天......什么?:)
这是简单的代码
package main
import "os"
func main() {
for {
go func() { os.Exit(0) }()
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:
jos*_*hlf 13
你已经遇到了Go调度程序的一个棘手的角落.答案是os.Exit 确实会导致整个过程退出,但是你采用它的方式,goroutines永远不会运行.
可能发生的是for循环不断向可用goroutine列表中添加新的goroutine,但由于整个进程只在一个OS线程中运行,因此Go调度程序从未实际调度过不同的goroutine,并且只是继续运行for循环没有运行你产生的任何goroutine.试试这个:
package main
import "os"
func main() {
for {
go func() { os.Exit(0) }()
func() {}()
}
}
Run Code Online (Sandbox Code Playgroud)
如果你在Go Playground上运行它,它应该工作(事实上,这是一个链接).
好吧,上面的代码在你的代码不起作用的事实应该是非常神秘的.这样做的原因是Go调度程序实际上是非抢占式的.这意味着除非给定的goroutine自愿决定给调度程序选择运行其他东西,否则没有别的东西可以运行.
现在显然你从来没有编写过包含命令的代码来给调度程序一个运行的机会.当编译代码时,Go编译器会自动将这些代码插入到代码中.以下是上述代码工作原理的关键:goroutine可能决定运行调度程序的一个时间是调用函数的时间.因此,通过添加func() {}()调用(显然什么都不做),我们允许编译器添加对调度程序的调用,从而为此代码提供了安排不同goroutine的机会.因此,其中一个产生的goroutine运行,调用os.Exit,并且进程退出.
编辑:如果编译器内联调用(或者,在这种情况下,完全删除它,因为它什么也不做),函数调用本身可能是不够的.runtime.Gosched()另一方面,保证工作.
您可以通过从函数返回来终止 Goroutine。如果需要确保goroutine运行完成,则需要等待goroutine完成。这通常是通过sync.WaitGroup或通过通道同步 goroutine 来完成的。
在您的示例中,您首先需要确保不可能产生无限数量的 goroutine。因为新的 goroutine 之间没有同步点main,所以不能保证它们中的任何一个都会os.Exit在主循环运行时执行调用。
等待任意数量的 goroutine 完成的常用方法是使用 a sync.WaitGroup,这将确保它们在退出之前全部执行完毕main。
wg := sync.WaitGroup{}
for i := 0; i < 10000; i++ {
wg.Add(1)
go func() { defer wg.Done() }()
}
wg.Wait()
fmt.Println("done")
Run Code Online (Sandbox Code Playgroud)