亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

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

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

Go
喵喵時光機 2021-12-07 14:20:22
我有一個算法非常簡單的研究程序。當成功到來時,goroutine 應該通過 os.Exit(0) 關閉(結束)。我等一天,兩天……什么?:)這是簡單的代碼package mainimport "os"func main() {    for {        go func() { os.Exit(0) }()    }}我的問題:為什么 os.Exit 不終止 goroutine?終止(停止)goroutine 執行的正確方法是什么?游樂場:http : //play.golang.org/p/GAeOI-1Ksc
查看完整描述

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(),另一方面,保證工作。


查看完整回答
反對 回復 2021-12-07
?
拉莫斯之舞

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")


查看完整回答
反對 回復 2021-12-07
?
慕村225694

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

        }

}


查看完整回答
反對 回復 2021-12-07
  • 3 回答
  • 0 關注
  • 286 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號