3 回答

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

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