首頁  >  文章  >  後端開發  >  chan chan 構造導致死鎖

chan chan 構造導致死鎖

王林
王林轉載
2024-02-05 22:54:03899瀏覽

chan chan 构造导致死锁

問題內容

我試著透過寫一小段程式碼來理解Go 中的chan chan 構造,如下所示,我希望3 個工作子程式處理10 個作業。每個工作子程式都有自己的通道,在其中接收要處理的「作業」。主 Go 程式透過從通道池中取得通道(因此是 chan chan 建構)來將作業分發到工作通道。

但是這段程式碼會導致死鎖情況!我嘗試了此程式碼的一些變體,但遇到了相同的錯誤。

是否是因為工作子程式永遠等待從其通道讀取作業?或者是由於其他原因(也許通道過早關閉等)?我對整個結構的理解顯然遺漏了一些東西。

有人可以幫我理解這個問題以及如何解決它嗎?

遊樂場中的程式碼,並根據要求複製到下面。

package main

import (
    "fmt"
    "sync"
)

type Job struct {
    ID int
}

func worker(id int, jobs <-chan Job, wg *sync.WaitGroup) {
    defer wg.Done()
    fmt.Printf("Worker %d starting\n", id)
    for job := range jobs {
        fmt.Printf("Worker %d processing job %d\n", id, job.ID)
    }
    fmt.Printf("Worker %d done\n", id)
}

func main() {
    numWorkers := 3
    maxJobs := 10
    var wg sync.WaitGroup
    // Create the pool of worker channels
    pool := make(chan chan Job, numWorkers)

    for i := 0; i < numWorkers; i++ {
        workerChan := make(chan Job) // Create a new channel for each worker
        pool <- workerChan           // Add the worker channel to the pool
        go worker(i, workerChan, &wg)
    }
    defer close(pool)
    // Create jobs and distribute them to workers
    for i := 0; i < maxJobs; i++ {
        job := Job{ID: i}
        wg.Add(1)
        workerChan := <-pool
        workerChan <- job
    }

    // Wait for all workers to complete
    wg.Wait()
    fmt.Println("All jobs are processed")
}

正確答案


首先:這裡不需要一個頻道的頻道。若要將工作指派給多個工作人員,您只需讓所有工作人員從單一共用通道讀取即可。當您向通道發送一件工作時,如果有可用的工作人員,其中一個將接收它,否則,通道發送操作將阻塞,直到有一個可用的工作人員為止。

如果您想為每個工作人員使用單獨的通道,您仍然不需要通道的通道,您只需要其中的一部分。每個工作人員將從專用管道收聽,您將自行管理工作分配:

numWorkers := 3
maxJobs := 10
var wg sync.WaitGroup
pool := make([]chan Job, numWorkers)
for i := 0; i < numWorkers; i++ {
    pool[i] = make(chan Job)
    wg.Add(1)
    go worker(i, pool[i], &wg)
}
for i := 0; i < maxJobs; i++ {
   job := Job{ID: i}
   pool[i%len(pool)] <- job
}
for _,c:=range pool {
   close(c)
}
wg.Wait()

您的程式碼有兩個問題:

  1. 您應該在建立 Goroutine 時新增至等待群組,而不是在將作業傳送到通道時新增
  2. 當您從頻道中讀取頻道時,該頻道將從池中刪除。所以當你讀取3個頻道後, workerChannel := <-pool 將會阻塞,因為沒有其他頻道。如果你堅持使用頻道的頻道,你必須把它放回去:
workerChan := <-pool
 workerChan <- job
 pool<-workerChan

這樣,您就可以將通道的通道用作循環隊列

  1. 關閉 pool 不會有任何效果。您必須關閉 pool 中的通道。

以上是chan chan 構造導致死鎖的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除