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

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

這段帶有無緩沖通道的代碼會導致 Go 中的 goroutine 泄漏嗎?

這段帶有無緩沖通道的代碼會導致 Go 中的 goroutine 泄漏嗎?

Go
侃侃爾雅 2023-06-19 17:03:47
我在用goroutines和channels寫一些golang并發代碼,懷疑我的代碼可能會導致goroutine泄露。我的情況類似下面的代碼,或者你可以打開這個go playground鏈接。func main() {? ? numCount := 3? ? numChan := make(chan int)? ? for i := 0; i < numCount; i++ {? ? ? ? go func(num int) {? ? ? ? ? ? fmt.Printf("Adding num: %d to chan\n", num)? ? ? ? ? ? numChan <- num? ? ? ? ? ? fmt.Printf("Adding num: %d to chan Done\n", num)? ? ? ? }(i)? ? }? ? time.Sleep(time.Second)? ? panic("Goroutine Resource Leak Test")}?在我看來,當主 goroutine 返回時,三個 goroutine 被阻止發送到無緩沖通道,并且會出現 goroutine 泄漏。表明So only if the channel was unbuffered the leak would occur.Go 編程語言建議:我們可以在測試期間使用一個方便的技巧:如果我們不在取消事件中從 main 返回,而是執行對 panic 的調用,那么運行時將轉儲程序中每個 goroutine 的堆棧。如果主 goroutine 是唯一剩下的 goroutine,那么它已經完成了自己的清理工作。但是如果還有其他goroutines,可能是沒有正確取消,或者已經取消了,但是取消需要時間;進行一些調查可能是值得的。恐慌轉儲通常包含足夠的信息來區分這些情況。因此,我panic("Goroutine Resource Leak Test")在 main 函數的末尾添加來驗證我的假設。但是,panic dump 僅包含 main goroutine,即沒有資源泄漏。Adding num: 0 to chanAdding num: 1 to chanAdding num: 2 to chanpanic: Goroutine Resource Leak Testgoroutine 1 [running]:main.main()? ? /tmp/sandbox011109649/prog.go:21 +0xc0誰能幫忙解釋一下為什么沒有 goroutine 泄漏,或者如果有泄漏,我應該如何獲得正確的恐慌轉儲任何建議將不勝感激,在此先感謝!
查看完整描述

1 回答

?
犯罪嫌疑人X

TA貢獻2080條經驗 獲得超4個贊

您的代碼的問題是雙重的。

首先,理論上存在goroutine泄漏,因為任何向容量為零的通道(無緩沖通道或已滿緩沖通道)發送值的嘗試都會阻塞發送 goroutine,直到在該通道上完成接收操作。

所以,是的,根據通道工作方式的定義,所有三個 goroutine 都將在numChan <- num語句中被阻止。

其次,由于 Go 的一些修改,panic默認情況下未處理的只轉儲恐慌 goroutine 的堆棧跟蹤。如果你想轉儲所有活動的 goroutines 的堆棧,你必須調整運行時——來自包的文檔runtime

GOTRACEBACK變量控制當 Go 程序由于未恢復的恐慌或意外的運行時條件而失敗時生成的輸出量。默認情況下,失敗會打印當前 goroutine 的堆棧跟蹤,省略運行時系統內部的函數,然后以退出代碼 2 退出。如果沒有當前 goroutine 或失敗是,則失敗會打印所有 goroutine 的堆棧跟蹤運行時內部。GOTRACEBACK=none完全省略 goroutine 堆棧跟蹤。GOTRACEBACK=single(默認值)的行為如上所述。GOTRACEBACK=all為所有用戶創建的 goroutines 添加堆棧跟蹤。GOTRACEBACK=system類似于“all”,但為運行時函數添加堆棧幀并顯示運行時內部創建的 goroutine。GOTRACEBACK=crash類似于“系統”,但以特定于操作系統的方式崩潰而不是退出。例如,在 Unix 系統上,崩潰SIGABRT引發核心轉儲。由于歷史原因,GOTRACEBACK設置 0、1 和 2 分別是 none、all 和 system 的同義詞。The runtime/debugpackage 的SetTraceback功能允許在運行時增加輸出量,但它不能減少到低于環境變量指定的量。


另請注意,您不能使用計時器進行(模擬)同步:在玩具示例中,這可能有效,但在現實生活中,沒有什么能阻止您的三個 goroutine 在您的主 goroutine 在調用中花費的時間跨度內沒有機會運行到time.Sleep——所以結果可能是任何數量的派生 goroutines 已經運行:從 0 到 3。

在那里添加一個事實,即當main退出運行時時,運行時只會殺死所有未完成的活動 goroutines,并且測試結果充其量可能是令人驚訝的。

因此,一個適當的解決方案是

  • 僅在需要的地方打印堆棧,

  • 確保通過匹配的接收同步發送:

package main


import (

? ? "fmt"

? ? "log"

? ? "runtime"

)


func dumpStacks() {

? ? buf := make([]byte, 32 * 1024)

? ? n := runtime.Stack(buf, true)

? ? log.Println(string(buf[:n]))

}


func main() {

? ? numCount := 3

? ? numChan := make(chan int, numCount)


? ? for i := 0; i < numCount; i++ {

? ? ? ? go func(num int) {

? ? ? ? ? ? fmt.Printf("Adding num: %d to chan\n", num)

? ? ? ? ? ? numChan <- num

? ? ? ? ? ? fmt.Printf("Adding num: %d to chan Done\n", num)

? ? ? ? }(i)

? ? }


? ? dumpStacks()


? ? for i := 0; i < numCount; i++ {

? ? ? ? <-numChan

? ? }

}

游樂場



查看完整回答
反對 回復 2023-06-19
  • 1 回答
  • 0 關注
  • 136 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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