猿问

Golang:为什么 os.Exit 在 goroutines 中不起作用

我有一个算法非常简单的研究程序。当成功到来时,goroutine 应该通过 os.Exit(0) 关闭(结束)。我等一天,两天……什么?:)


这是简单的代码


package main


import "os"


func main() {

    for {

        go func() { os.Exit(0) }()

    }

}

我的问题:


为什么 os.Exit 不终止 goroutine?

终止(停止)goroutine 执行的正确方法是什么?

游乐场:http : //play.golang.org/p/GAeOI-1Ksc


喵喵时光机
浏览 234回答 3
3回答

呼如林

您遇到了 Go 调度程序的一个棘手问题。答案是这os.Exit 确实会导致整个进程退出,但是按照您的方式,goroutines 从未运行。可能发生的情况是 for 循环不断向可用 goroutine 列表中添加新的 goroutine,但是由于整个进程仅在一个 OS 线程中运行,因此 Go 调度程序从未真正安排过不同的 goroutine,只是继续运行它for 循环而无需运行您生成的任何 goroutine。试试这个:package mainimport "os"func main() {    for {        go func() { os.Exit(0) }()        func() {}()    }}如果您在 Go Playground 上运行它,它应该可以工作(实际上,这是一个链接)。好的,上面的代码可以运行而你的代码不运行的事实应该很神秘。这样做的原因是 Go 调度程序实际上是非抢占的。这意味着除非给定的 goroutine 自愿决定给调度程序运行其他东西的选项,否则其他任何东西都不会运行。显然,您从未编写过包含让调度程序有机会运行的命令的代码。发生的情况是,当您的代码被编译时,Go 编译器会自动将这些插入到您的代码中。这是上述代码为何起作用的关键:goroutine 可能决定运行调度程序的时间之一是调用函数时。因此,通过添加func() {}()调用(显然什么都不做),我们允许编译器添加对调度程序的调用,让这段代码有机会调度不同的 goroutine。因此,产生的 goroutine 之一运行,调用os.Exit,然后进程退出。编辑:在编译器内联调用的情况下,函数调用本身可能是不够的(或者,在这种情况下,因为它什么都不做而完全删除它)。runtime.Gosched(),另一方面,保证工作。

拉莫斯之舞

您可以通过从函数返回来终止 goroutine。如果需要确保 goroutine 运行完成,则需要等待 goroutine 完成。这通常是通过sync.WaitGroup, 或通过通道同步 goroutine 来完成的。在您的示例中,您首先需要确保不可能产生无限数量的 goroutine。因为main新的 goroutine之间没有同步点,所以不能保证os.Exit在主循环运行时它们中的任何一个都会执行调用。等待任意数量的 goroutine 完成的通常方法是使用 a sync.WaitGroup,这将确保它们在main退出之前都已执行。wg := sync.WaitGroup{}for i := 0; i < 10000; i++ {&nbsp; &nbsp; wg.Add(1)&nbsp; &nbsp; go func() { defer wg.Done() }()}wg.Wait()fmt.Println("done")

慕村225694

实施死手或终止开关package mainimport (&nbsp; &nbsp; &nbsp; &nbsp; "fmt"&nbsp; &nbsp; &nbsp; &nbsp; "time"&nbsp; &nbsp; &nbsp; &nbsp; "os")const maxNoTickle = 50&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // will bail out after this many no ticklesconst maxWorking = 20&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// pretendWork() will tickle this many timesconst deadTicks = 250&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// milliseconds for deadHand() to check for ticklesconst reportTickles = 4&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// consecutive tickles or no tickles to print somethingvar (&nbsp; &nbsp; &nbsp; &nbsp; tickleMe bool&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// tell deadHand() we're still alive&nbsp; &nbsp; &nbsp; &nbsp; countNoTickle int&nbsp; &nbsp; &nbsp; &nbsp;// consecutive no tickles&nbsp; &nbsp; &nbsp; &nbsp; countGotTickle int&nbsp; &nbsp; &nbsp; // consecutive tickles)/***&nbsp; &nbsp; &nbsp; &nbsp;deadHand() - callback to kill program if nobody checks in after some period*/func deadHand() {&nbsp; &nbsp; &nbsp; &nbsp; if !tickleMe {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; countNoTickle++&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; countGotTickle = 0&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if countNoTickle > maxNoTickle {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("No tickle max time reached. Bailing out!")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // panic("No real panic. Just checking stack")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; os.Exit(0)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if countNoTickle % reportTickles == 0 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // print dot for consecutive no tickles&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf(".")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; countNoTickle = 0&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; countGotTickle++&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tickleMe = false&nbsp; &nbsp; &nbsp; &nbsp; // FIXME: might have race condition here&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if countGotTickle % reportTickles == 0 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // print tilda for consecutive tickles&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("~")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; // call ourselves again&nbsp; &nbsp; &nbsp; &nbsp; time.AfterFunc(deadTicks * time.Millisecond, deadHand)}/***&nbsp; &nbsp; &nbsp; &nbsp;init() - required to start deadHand*/func init() {&nbsp; &nbsp; &nbsp; &nbsp; time.AfterFunc(250 * time.Millisecond, deadHand)&nbsp; &nbsp; &nbsp; &nbsp; tickleMe = true}/***&nbsp; &nbsp; &nbsp; &nbsp;pretendWork() - your stuff that does its thing*/func pretendWork() {&nbsp; &nbsp; &nbsp; &nbsp; for count := 0; count < maxWorking; count++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tickleMe = true // FIXME: might have race condition here&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // print W pretending to be busy&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Printf("W")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; time.Sleep(100 * time.Millisecond)&nbsp; &nbsp; &nbsp; &nbsp; }}func main() {&nbsp; &nbsp; &nbsp; &nbsp; go workTillDone()&nbsp; &nbsp; &nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // oops, program went loop-d-loopy&nbsp; &nbsp; &nbsp; &nbsp; }}
随时随地看视频慕课网APP

相关分类

Go
我要回答