1 回答

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/debug
package 的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
? ? }
}
游樂場。
- 1 回答
- 0 關注
- 136 瀏覽
添加回答
舉報