當填充通道的函數呼叫未嵌入Goroutine中時,會出現死鎖的原因是因為通道的傳送和接收操作是阻塞的。如果在主Goroutine中呼叫填充通道的函數,並且該函數內部沒有將填充操作放入新的Goroutine中運行,那麼主Goroutine會一直等待通道有足夠的空間來接收數據,而填充操作又無法進行,從而導致死鎖的產生。因此,為了避免死鎖,我們需要在填充通道的操作中使用Goroutine來進行並發執行,以確保填充操作和接收操作可以同時進行。
我知道 sync
套件及其 waitgroup
選項,我不想將其用於此測試。我正在測試一種信號量。
所以我有:
package main import ( "fmt" "os" "time" ) func main() { fmt.print("wassap") jobs := make(chan int) processstarted := make(chan struct{}, 1) processcompleted := make(chan struct{}, 1) createjobs(jobs) go func() { worker(jobs, processstarted, processcompleted) }() go func() { sync(processstarted, processcompleted) }() time.sleep(3600 * time.second) fmt.print("\nend of main...") interrupt := make(chan os.signal) <-interrupt } func createjobs(jobs chan<- int) { defer close(jobs) for i := 1; i < 20; i++ { jobs <- i } } func worker(jobs <-chan int, processstarted <-chan struct{}, processcompleted <-chan struct{}) { for { select { case i := <-jobs: fmt.printf("\nfetching job #%d from channel", i) time.sleep(2 * time.second) case <-processstarted: fmt.print("\nprocess started. waiting for it to be completed") <-processcompleted fmt.print("\nprocess completed") } } } func sync(processstarted chan<- struct{}, processcompleted chan<- struct{}) { // acquire semaphore. send signal to channel to indicate that it is busy processstarted <- struct{}{} for i := 1; i < 5; i++ { fmt.printf("\nprocessing %d", i) time.sleep(5 * time.second) } // release semaphore processcompleted <- struct{}{} }
我想要測試的非常簡單:我有一個 createjobs
函數,其唯一目的是將元素添加到通道,在本例中是一個 int 通道。然後我有一個 worker
將從該通道中提取物件並在提取下一個元素之前休眠 2 秒。
現在,還有同步功能。此函數的唯一目的是模擬 worker
執行階段啟動的進程。如果此進程處於活動狀態,則在sync
結束時應停止處理jobs
元素,這就是為什麼我有兩個通道,一個表示進程已啟動,另一個表示進程結束。
運行我的程式碼時出現以下錯誤:
fatal error: all goroutines are asleep - deadlock!
如果我修改 createjobs
的呼叫方式,將其包裝在如下所示的 goroutine 中:
go func() { createJobs(jobs) }()
然後我的程式碼運行正確。
我只是想了解為什麼會發生這種情況。我的意思是: main
例程正在執行,然後它呼叫createjobs
(無換行),因此main
例程應該被阻止,直到此呼叫結束。一旦 createjobs
結束,就表示頻道中有元素了。 main
繼續執行並啟動其他 goroutine worker
和 sync
來完成它們的工作。在 main
結束之前,我只是添加一個睡眠程序,以便為之前創建的 goroutine 提供完成時間。
我不是問這個問題的其他解決方案,我只是想知道當 createjobs
發生在 goroutine 之外時會發生什麼。
您將 jobs
宣告為無緩衝通道,然後嘗試將 20 個值同步推入其中。當您呼叫 createjobs(jobs)
時,這將阻止您的主函數。
將第 13 行改為:
jobs := make(chan int, 20)
...將解決僵局。
編輯 - 評論中要求的澄清:
無緩衝通道沒有容量,並且會阻止生產者的執行,直到消費者收到訊息為止。
無緩衝通道的一個很好的類比是管道,在本例中,過程如下所示:
+------------------+ +------------+ +-------------+ | PRODUCER | | PIPE | | CONSUMER | | +---->| +----->| | | createJobs(jobs) | | unbuffered | | worker(...) | | | | channel | | | +------------------+ +------------+ +-------------+
發生死鎖是因為 createjobs(jobs)
被同步調用,而且還沒有消費者在運作。
當在 goroutine 中呼叫函數(producer)時它可以工作,因為基本上插入通道和讀取通道是並行發生的?
是的。如果生產者被非同步調用,它不會阻塞 main()
函數,因此消費者也將有機會被調用。在這種情況下,生產者將一一推送其所有任務,就像工作人員一一消費它們一樣。
以上是當填充通道的函數呼叫未嵌入 Goroutine 中時,為什麼會出現死鎖?的詳細內容。更多資訊請關注PHP中文網其他相關文章!