我正在練習通過同時將計算分成 100 個組來計算階乘的挑戰,我在 WaitGroups 上解決了很多問題,但仍然在函數中calculateFactorial我在通道部分的范圍上遇到了死鎖。希望有人能指出這里的問題,謝謝。更新:它通過簡單地將 更改為緩沖通道解決了上述代碼中的問題。你永遠不應該僅僅為了修復死鎖而添加緩沖。如果您的程序死鎖,從零緩沖開始并仔細考慮依賴關系,修復起來要容易得多。然后在您知道不會死鎖時添加緩沖。那么誰能幫我弄清楚如何不為此使用緩沖通道?是否可以?此外,我對導致死鎖的確切原因做了一些研究。如果通道是無緩沖的,則發送方會阻塞,直到接收方收到該值。如果通道有緩沖區,發送方只會阻塞直到值被復制到緩沖區;如果緩沖區已滿,這意味著等待某個接收者檢索到一個值。否則說:當通道已滿時,發送方等待另一個 goroutine 通過接收來騰出一些空間你可以看到一個無緩沖的通道總是滿的:必須有另一個 goroutine 來接收發送者發送的內容。所以在我原來的情況下,可能導致僵局的原因可能是:頻道上的范圍沒有接收到?通道上的范圍未在單獨的 go 例程中接收。?沒有oneResult正確關閉,所以 range over channel 不知道盡頭在哪里?對于數字 3,我不知道關閉 before range over 是否有任何錯誤oneResult,因為這種模式出現在互聯網上的許多示例中。如果是 3 號,是不是等待組有問題?我得到了另一篇與我的情況非常相似的文章,他使用for { select {} }無限循環作為 range over 的替代方法,似乎解決了他的問題。go func() {? ? ? ? for{? ? ? ? ? ? select {? ? ? ? ? ? case p := <-pch:? ? ? ? ? ? ? ? findcp(p)? ? ? ? ? ? }? ? ? ? }? ? }()第 2 課 — 無緩沖通道無法保存值(是的,它就在名稱“無緩沖”中),因此無論發送到該通道的什么,都必須立即由其他代碼接收。接收代碼必須在不同的 goroutine 中,因為一個 goroutine 不能同時做兩件事:它不能發送和接收;它必須是一個或另一個。
2 回答

慕哥9229398
TA貢獻1877條經驗 獲得超6個贊
死鎖不在 range-over-channel 循環上。如果您在操場上運行代碼,您會在堆棧跟蹤的頂部看到錯誤是由wg2.Wait
(操場上的第 88 行并由堆棧跟蹤指向)引起的。同樣在堆棧跟蹤中,您可以看到所有因死鎖而未完成的 goroutine,這是因為oneResult<-t
從未完成,因此循環中啟動的 goroutine 都沒有完成。
所以主要問題在這里:
wg2.Wait()
close(oneResult)
// ...
for n := range oneResult{
// ...
我想,在封閉的頻道上循環也不是你想要的。但是,即使您沒有關閉頻道,該循環也永遠不會開始,因為wg2.Wait()
它會等到完成。
oneResult?<-?t wg2.Done()
但它永遠不會完成,因為它依賴于已經運行的循環。該線路oneResult <- t
不會完成,除非另一側有人從該通道接收信號,這是您的循環,但是該通道范圍循環仍在等待完成wg2.Wait()
。
所以本質上你在通道的發送者和接收者之間有一個“循環依賴”。
要解決此問題,您需要允許循環開始從通道接收數據,同時仍確保該通道在完成后關閉。你可以通過將兩條等待和關閉線包裝到它們自己的 goroutine 中來做這件事。
https://play.golang.com/p/rwwCFVszZ6Q
- 2 回答
- 0 關注
- 152 瀏覽
添加回答
舉報
0/150
提交
取消