Go の外部関数で sync.WaitGroup を使用するときにデッドロックを回避するにはどうすればよいですか?

Mary-Kate Olsen
リリース: 2024-11-05 22:03:02
オリジナル
886 人が閲覧しました

How to Avoid Deadlocks When Using sync.WaitGroup with External Functions in Go?

外部関数で sync.WaitGroup を利用するためのベスト プラクティス

Go で同時実行性に対処する場合、sync.WaitGroup を効果的に利用することが重要です。この記事では、待機グループを引数として外部関数に渡すときに発生する一般的な問題について説明します。

問題:

次のコードを考えてみましょう:

<code class="go">package main

import (
    "fmt"
    "sync"
)

func main() {
    ch := make(chan int)
    var wg sync.WaitGroup
    wg.Add(2)
    go Print(ch, wg) //
    go func(){

        for i := 1; i <= 11; i++ {
            ch <- i
        }

        close(ch)
        defer wg.Done()


    }()

    wg.Wait() //deadlock here
}

// Print prints all numbers sent on the channel.
// The function returns when the channel is closed.
func Print(ch <-chan int, wg sync.WaitGroup) {
    for n := range ch { // reads from channel until it's closed
        fmt.Println(n)
    }
    defer wg.Done()
}</code>
ログイン後にコピー

このコードでは、指定された行でデッドロックが発生し、プログラムは 11 までではなく 1 から 10 までしか印刷しません。このエラーは、sync.WaitGroup のコピーを Print メソッドに渡すことで発生し、これが妨げになります。 Done メソッドへの予期された呼び出しです。

解決策 1:

この問題を解決するには、代わりに待機グループへのポインタを渡します:

<code class="go">package main

import (
    "fmt"
    "sync"
)

func main() {    
    ch := make(chan int)

    var wg sync.WaitGroup
    wg.Add(2)    

    go Print(ch, &wg)

    go func() {  
        for i := 1; i <= 11; i++ {
            ch <- i
        }
        close(ch)
        defer wg.Done()
    }()          

    wg.Wait() //deadlock here
}                

func Print(ch <-chan int, wg *sync.WaitGroup) {
    for n := range ch { // reads from channel until it's closed
        fmt.Println(n)
    }            
    defer wg.Done()
}</code>
ログイン後にコピー

wg のアドレスを渡すと、Print メソッドが main 関数で待機している待機グループの Done メソッドを呼び出すようになります。

解決策 2: 簡素化された Print メソッド

また、待機操作の知識が必要ないため、Print メソッドは WaitGroup 引数を削除することで簡素化できます。

<code class="go">package main

import (
    "fmt"
)

func main() {    
    ch := make(chan int)
    go func() {  
        for i := 1; i <= 11; i++ {
            ch <- i
        }
        close(ch)
    }()          

    for n := range ch { // reads from channel until it's closed
        fmt.Println(n)
    }            
}                </code>
ログイン後にコピー

このシナリオでは、メインのゴルーチンがチャネルを直接受信して出力します。待機グループを含まないその値。このアプローチにより、必要な機能が維持され、Print メソッド内での WaitGroup 管理の必要がなくなります。

結論:

sync.WaitGroup を引数として外部関数に渡す場合、関数が待機中の待機グループへの正しい参照を確実に受け取ることが重要です。待機グループを直接処理するように関数をリファクタリングするか、待機グループへのポインタを渡すと、デッドロック エラーを効果的に防止し、適切な同時実行制御を確保できます。

以上がGo の外部関数で sync.WaitGroup を使用するときにデッドロックを回避するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!