3 回答

TA貢獻1946條經驗 獲得超3個贊
您的ScheduleWorks
函數在主協程(即運行該main()
函數的協程,程序在該協程中啟動)中通過input
. AWorker
接收它,并通過 發送另一個值output
。但是此時沒有人接收output
,因此程序無法繼續,主 goroutine 將下一個值發送到另一個Worker
.
對每個 Worker 重復這個推理。你有runtime.NumCPU()
工人,這可能少于numJobs
. 比方說runtime.NumCPU() == 4
,所以你有 4 個工人。最后,您已成功發送 4 個值,每個值都是一對一的Worker
。由于沒有人從 讀取output
,所有 Worker 都忙于嘗試發送,因此它們無法通過 接受更多數據input
,因此第五個input <- i
將掛起。此時每個 goroutine 都在等待;這就是僵局。
您會注意到,如果您啟動 20 個或更多的 Worker 而不是 runtime.NumCPU()
,則該程序可以運行。那是因為主 goroutine 可以通過 發送它想要的所有內容input
,因為有足夠的工作人員來接收它們。
如果不是所有這些,而是將input <- i
循環放在另一個 goroutine 中,就像在您成功的示例中一樣,main
goroutine(在其中ScheduleWorks
運行)可以繼續并從output
. 所以,每次這個新的 goroutine 發送一個值時,worker 發送另一個值,output
主 goroutine 得到這個輸出,worker 可以接收另一個值。沒有人等待,程序成功了。

TA貢獻1824條經驗 獲得超8個贊
這是因為 Go 中的所有內容默認都是阻塞的。
當您在無緩沖通道上發送第一個值時,它會阻塞,直到接收器從通道中取出該值。
可以通過添加“容量”來緩沖通道。
例如:
make(chan int, 20) // Make a buffered channel of int with capacity 20
從Go 規范:
容量(以元素數為單位)設置通道中緩沖區的大小。如果容量大于零,則通道是異步的:如果緩沖區未滿(發送)或非空(接收),則通信操作成功而不會阻塞,并且元素按發送順序接收。如果容量為零或不存在,則只有當發送方和接收方都準備好時,通信才能成功。
您可以通過使用緩沖通道而不是非緩沖通道來使原始函數工作,但是將函數調用包裝在 goroutine 中可能是更好的方法,因為它實際上是并發的。
來自Effective Go(完整閱讀此文檔!它可能是 Stack Overflow 上 Go 答案中鏈接最多的文檔):
接收器總是阻塞直到有數據要接收。如果通道未緩沖,則發送方將阻塞,直到接收方收到該值。如果通道有緩沖區,則發送方只會阻塞,直到值被復制到緩沖區;如果緩沖區已滿,這意味著等待某個接收器檢索到一個值。
如果您使用緩沖通道,那么您只是填充通道,繼續前進,然后再次排空。不能同時進行。
例子:
改變
input, output := make(chan int), make(chan int)
到
input, output := make(chan int, 20), make(chan int, 20)
- 3 回答
- 0 關注
- 261 瀏覽
添加回答
舉報