我一直在研究 Golang,并通過其創(chuàng)新的 goroutines 構(gòu)造來了解它的并發(fā)性以及它的僅協(xié)程通道模型的實施有多好。我立即發(fā)現(xiàn)麻煩的一件事是該方法的使用Wait(),該方法用于等待父 goroutine 內(nèi)產(chǎn)生的多個未完成的 goroutine 完成。引用Golang 文檔等待可用于阻塞,直到所有 goroutine 完成事實上,許多 Go 開發(fā)人員將其規(guī)定 Wait()為實現(xiàn)并發(fā)的首選方式,這似乎與 Golang 使開發(fā)人員能夠編寫高效軟件的使命背道而馳,因為阻塞是低效的,而真正的異步代碼永遠不會阻塞。阻塞的進程 [或線程] 是等待某個事件的進程,例如資源變得可用或 I/O 操作完成。換句話說,阻塞的線程將花費 CPU 周期做無用的事情,只是反復檢查當前運行的任務(wù)是否可以停止等待并繼續(xù)執(zhí)行。在真正的異步代碼中,當協(xié)程遇到無法繼續(xù)執(zhí)行直到結(jié)果到達的情況時,它必須將其執(zhí)行交給調(diào)度程序而不是阻塞,方法是將其狀態(tài)從running切換到waiting,以便調(diào)度程序可以開始執(zhí)行下一個 -來自可運行隊列的內(nèi)聯(lián)協(xié)程。只有當它需要的結(jié)果到達時,等待協(xié)程才應(yīng)該將其狀態(tài)從等待更改為可運行。因此,由于Wait()阻塞直到 x 數(shù)量的 goroutine 被調(diào)用Done(),調(diào)用的 goroutineWait()將始終保持在可運行或運行狀態(tài),浪費 CPU 周期并依賴調(diào)度程序搶占長時間運行的 goroutine 只是將其狀態(tài)從運行更改為可運行,而不是將其更改為應(yīng)有的等待狀態(tài)。如果這一切都是真的,并且我理解如何Wait()正確工作,那么為什么人們不使用內(nèi)置的 Go 通道來完成等待子 goroutines 完成的任務(wù)?如果我理解正確,發(fā)送到緩沖通道和從任何通道讀取都是異步操作,這意味著調(diào)用它們會使 goroutine 進入等待狀態(tài),那么為什么它們不是首選方法呢?我引用的文章給出了幾個例子。以下是作者所說的“老派”方式:package mainimport ( "fmt" "time")func main() { messages := make(chan int) go func() { time.Sleep(time.Second * 3) messages <- 1 }() go func() { time.Sleep(time.Second * 2) messages <- 2 }() go func() { time.Sleep(time.Second * 1) messages <- 3 }() for i := 0; i < 3; i++ { fmt.Println(<-messages) }}這是首選的“規(guī)范”方式:package mainimport ( "fmt" "sync" "time")func main() { messages := make(chan int) var wg sync.WaitGroup wg.Add(3) go func() { defer wg.Done() time.Sleep(time.Second * 3) messages <- 1 }() go func() { defer wg.Done() time.Sleep(time.Second * 2) messages <- 2 }() go func() { defer wg.Done() time.Sleep(time.Second * 1) messages <- 3 }() wg.Wait() for i := range messages { fmt.Println(i) }}我可以理解第二個可能比第一個更容易理解,但第一個是異步的,沒有協(xié)程阻塞,第二個有一個阻塞的協(xié)程:運行主函數(shù)的協(xié)程。這是另一個Wait()被普遍接受的方法的例子。如果創(chuàng)建低效的阻塞線程,為什么 Go 社區(qū)不Wait()將其視為反模式?為什么在這種情況下通道不是大多數(shù)人首選的,因為它們可以用來保持所有代碼異步和線程優(yōu)化?
1 回答

ibeautiful
TA貢獻1993條經(jīng)驗 獲得超6個贊
您對“阻塞”的理解不正確。諸如WaitGroup.Wait()
或通道接收之類的阻塞操作(當沒有要接收的值時)只會阻塞 goroutine 的執(zhí)行,它們不會(必然)阻塞用于執(zhí)行 goroutine(的語句)的 OS 線程。
每當遇到阻塞操作(例如上面提到的)時,goroutine 調(diào)度程序可能(并且它會)切換到另一個可能繼續(xù)運行的 goroutine。在調(diào)用期間沒有(重要的)CPU 周期丟失WaitGroup.Wait()
,如果有其他 goroutines 可能繼續(xù)運行,它們將會。
- 1 回答
- 0 關(guān)注
- 171 瀏覽
添加回答
舉報
0/150
提交
取消