ホームページ >バックエンド開発 >Golang >chan chan コンストラクトによりデッドロックが発生する

chan chan コンストラクトによりデッドロックが発生する

王林
王林転載
2024-02-05 22:54:03912ブラウズ

chan chan 构造导致死锁

質問の内容

私は、次のような小さなコードを書いて、Go の chan chan 構造を理解しようとしています。以下に、I 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")
}

正解


まず第一に、ここには複数のチャネルは必要ありません。複数のワーカーに作業を分散するには、すべてのワーカーが単一の共有チャネルから読み取られるようにするだけです。作業内容をチャネルに送信するとき、使用可能なワーカーがあればそのうちの 1 人がそれを受信します。それ以外の場合、使用可能なワーカーが見つかるまでチャネル送信操作はブロックされます。

ワーカーごとに個別のチャネルを使用する場合でも、チャネルのチャネルは必要ありません。チャネルのサブセットだけが必要です。各従業員は専用チャネルから音声を聞き、あなたは自分の仕事の割り当てを管理します:

リーリー

コードには 2 つの問題があります:

  1. ジョブをチャネルに送信するときではなく、Goroutine を作成するときに待機グループに追加する必要があります。
  2. チャネルからチャネルを読み取ると、チャネルはプールから削除されます。したがって、3 つのチャネルを読み取った後、他にチャネルがないため、
  3. workerChannel := <-pool はブロックされます。どうしてもそのチャンネルのチャンネルを使用したい場合は、元に戻す必要があります:
  4. リーリー
これにより、チャネルのチャネルを循環キューとして使用できます

    Close
  1. pool は効果がありません。 pool のチャネルを閉じる必要があります。

以上がchan chan コンストラクトによりデッドロックが発生するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はstackoverflow.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。