2017-08-24 119 views
1
package main 

import (
    "fmt" 
    "time" 
) 

func main() { 
    p := producer() 
    for c := range p { 
     fmt.Println(c) 
    } 
} 

func producer() <-chan string { 
    ch := make(chan string) 
    go func() { 
     for i := 0; i < 5; i++ { 
      ch <- fmt.Sprint("hello", i) 
      time.Sleep(1 * time.Second) 
     } 
     // commented the below to show the issue 
     // close(ch) 
    }() 
    return ch 
} 

運行上面的代碼將打印5條消息,然後給出一個「所有去例程是睡眠 - 死鎖錯誤」。我明白,如果我關閉了頻道,錯誤消失了。瞭解走通道死鎖

我想了解的是,運行時如何知道代碼將無限期地等待在通道上,並且沒有其他任何事情將數據發送到通道中。

現在,如果我爲main()函數添加額外的例程,它不會拋出任何錯誤並持續等待通道。

go func() { 
     for { 
      time.Sleep(2 * time.Millisecond) 
     } 
    }() 

那麼,這是否意味着.. Go運行時只是尋找一個運行去例程可能將數據發送到通道中,因此不扔僵局錯誤的存在?

回答

3

當所有goroutines在通道和互斥操作上被阻塞時,運行時恐慌與「所有去例程是睡眠 - 死鎖錯誤」錯誤。

睡覺的goroutine不會阻止這些操作之一。沒有僵局,因此沒有恐慌。

4

如果你想要一些更深入地轉到如何實現死鎖檢測,看看在代碼的地方拋出的"all goroutines are asleep - deadlock!"https://github.com/golang/go/blob/master/src/runtime/proc.go#L3751

它看起來像圍棋運行時將如何一些相當簡單的會計有很多goroutines,有多少人閒着,有多少人正在睡覺(不知道通道I/O上哪一個人會睡覺)。在任何給定時間(與運行時的其餘部分一起序列化),它只是執行一些算術運算並檢查是否all - idle - locked > 0 ...如果是,那麼程序仍然可以取得進展...如果它是0,那麼你肯定是死鎖了。

可能你可以通過阻止goroutine通過無限循環睡眠來引入一個活鎖(就像你在實驗中所做的一樣,顯然睡眠的定時器在運行時並不一樣)。在這種情況下,運行時將無法檢測到死鎖,並永遠運行。此外,我不確定運行時間是否檢查死鎖 - 如果您有興趣,可以進一步檢查誰調用checkdead()可能會產生一些洞察。

卸棄我不是一個圍棋核心開發者,我只是玩一個在電視上:-)

+0

感謝@Eddy R代表的信息。嘗試給+1,但由於我的低點,系統不允許。 – tblogger