3 回答

TA貢獻1798條經驗 獲得超3個贊
您遇到了 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() {}()
}
}
如果您在 Go Playground 上運行它,它應該可以工作(實際上,這是一個鏈接)。
好的,上面的代碼可以運行而你的代碼不運行的事實應該很神秘。這樣做的原因是 Go 調度程序實際上是非搶占的。這意味著除非給定的 goroutine 自愿決定給調度程序運行其他東西的選項,否則其他任何東西都不會運行。
顯然,您從未編寫過包含讓調度程序有機會運行的命令的代碼。發生的情況是,當您的代碼被編譯時,Go 編譯器會自動將這些插入到您的代碼中。這是上述代碼為何起作用的關鍵:goroutine 可能決定運行調度程序的時間之一是調用函數時。因此,通過添加func() {}()調用(顯然什么都不做),我們允許編譯器添加對調度程序的調用,讓這段代碼有機會調度不同的 goroutine。因此,產生的 goroutine 之一運行,調用os.Exit,然后進程退出。
編輯:在編譯器內聯調用的情況下,函數調用本身可能是不夠的(或者,在這種情況下,因為它什么都不做而完全刪除它)。runtime.Gosched(),另一方面,保證工作。

TA貢獻1820條經驗 獲得超10個贊
您可以通過從函數返回來終止 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++ {
wg.Add(1)
go func() { defer wg.Done() }()
}
wg.Wait()
fmt.Println("done")

TA貢獻1880條經驗 獲得超4個贊
實施死手或終止開關
package main
import (
"fmt"
"time"
"os"
)
const maxNoTickle = 50 // will bail out after this many no tickles
const maxWorking = 20 // pretendWork() will tickle this many times
const deadTicks = 250 // milliseconds for deadHand() to check for tickles
const reportTickles = 4 // consecutive tickles or no tickles to print something
var (
tickleMe bool // tell deadHand() we're still alive
countNoTickle int // consecutive no tickles
countGotTickle int // consecutive tickles
)
/**
* deadHand() - callback to kill program if nobody checks in after some period
*/
func deadHand() {
if !tickleMe {
countNoTickle++
countGotTickle = 0
if countNoTickle > maxNoTickle {
fmt.Println("No tickle max time reached. Bailing out!")
// panic("No real panic. Just checking stack")
os.Exit(0)
}
if countNoTickle % reportTickles == 0 {
// print dot for consecutive no tickles
fmt.Printf(".")
}
} else {
countNoTickle = 0
countGotTickle++
tickleMe = false // FIXME: might have race condition here
if countGotTickle % reportTickles == 0 {
// print tilda for consecutive tickles
fmt.Printf("~")
}
}
// call ourselves again
time.AfterFunc(deadTicks * time.Millisecond, deadHand)
}
/**
* init() - required to start deadHand
*/
func init() {
time.AfterFunc(250 * time.Millisecond, deadHand)
tickleMe = true
}
/**
* pretendWork() - your stuff that does its thing
*/
func pretendWork() {
for count := 0; count < maxWorking; count++ {
tickleMe = true // FIXME: might have race condition here
// print W pretending to be busy
fmt.Printf("W")
time.Sleep(100 * time.Millisecond)
}
}
func main() {
go workTillDone()
for {
// oops, program went loop-d-loopy
}
}
- 3 回答
- 0 關注
- 286 瀏覽
添加回答
舉報