ホームページ  >  記事  >  バックエンド開発  >  Golang WaitGroup とコルーチン プールの効率的な組み合わせ

Golang WaitGroup とコルーチン プールの効率的な組み合わせ

王林
王林オリジナル
2023-09-28 17:22:491211ブラウズ

Golang WaitGroup和协程池的高效结合

Golang WaitGroup とコルーチン プールを効率的に組み合わせるには、特定のコード例が必要です

はじめに:
Go 言語は、同時プログラミングを重視した言語です。効率的な同時実行は次のとおりです。 goroutine を通じて実現されます。複数のタスクを同時に実行する必要がある一部のシナリオでは、WaitGroup とコルーチン プールを組み合わせることで、プログラムの実行効率とリソース使用率を効果的に向上させることができます。この記事では、Golang で WaitGroup とコルーチン プールを使用して効率的な同時プログラミングを実現する方法を紹介し、具体的なコード例を示します。

1. WaitGroup の概要
WaitGroup は、コルーチンのグループの実行の完了を待つために使用される Go 言語のツールです。そのソース コードは次のように定義されています。

type WaitGroup struct {
    noCopy noCopy

    // 64位的值:高32位存储计数器,低32位存储等待计数器
    // 这个变量可以被原子操作加载和存储。
    // 在64位同步原语中,它必须在64位边界对齐。
    // 是一个强制的要求。
    state1 [3]uint32
}

WaitGroup は通常、メインの goroutine で作成され、その後、main goroutine 内の各サブ goroutine が Add メソッドを呼び出してカウンタを増加させ、実行が完了した後、 Done メソッドはカウンターをデクリメントするために使用されます。メインのゴルーチンは、Wait メソッドを通じてカウンターがゼロに戻るのを待つことができます。具体的なサンプル コードは次のとおりです。

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    wg.Add(3)

    go func() {
        defer wg.Done()
        fmt.Println("Task 1 executing")
    }()

    go func() {
        defer wg.Done()
        fmt.Println("Task 2 executing")
    }()

    go func() {
        defer wg.Done()
        fmt.Println("Task 3 executing")
    }()

    wg.Wait()
    fmt.Println("All tasks completed")
}

上の例では、WaitGroup オブジェクトを作成し、Add メソッドを呼び出してカウンタを増やします。次に、3 つのサブゴルーチンを作成し、各ゴルーチンが実行された後、Done メソッドによってカウンターがデクリメントされます。最後に、メインのゴルーチンは、Wait メソッドを呼び出してカウンターがゼロに戻るのを待ちます。すべてのタスクが完了すると、プログラムは「すべてのタスクが完了しました」と出力します。

2. コルーチン プールの概要
並行プログラミングでは、コルーチン プール (ゴルーチン プール) がよく使用されるモードです。固定数のゴルーチンを作成し、それらにタスクを均等に分散することで、ゴルーチンを絶えず作成および破棄するオーバーヘッドを回避できます。 Go 言語では、チャネルを使用してコルーチン プールを実装できます。具体的なサンプル コードは次のとおりです。

package main

import (
    "fmt"
    "sync"
)

func worker(id int, jobs <-chan int, results chan<- int) {
    for j := range jobs {
        fmt.Println("Worker", id, "started job", j)
        fib := fibonacci(j)
        fmt.Println("Worker", id, "finished job", j)
        results <- fib
    }
}

func fibonacci(n int) int {
    if n <= 1 {
        return n
    }

    return fibonacci(n-1) + fibonacci(n-2)
}

const numJobs = 5
const numWorkers = 3

func main() {
    jobs := make(chan int, numJobs)
    results := make(chan int, numJobs)

    var wg sync.WaitGroup
    wg.Add(numWorkers)

    for w := 1; w <= numWorkers; w++ {
        go func(id int) {
            defer wg.Done()
            worker(id, jobs, results)
        }(w)
    }

    for j := 1; j <= numJobs; j++ {
        jobs <- j
    }
    close(jobs)

    wg.Wait()

    for r := 1; r <= numJobs; r++ {
        fmt.Println(<-results)
    }
}

上の例では、ジョブ チャネルから保留中のタスクを読み取り、タスクを実行して結果を結果チャネルに送信するワーカー関数を定義しました。タスクを分散して結果を取得することでコルーチンプールの機能を実装するために、ジョブチャネルと結果チャネルを作成しました。

main 関数では、WaitGroup を使用して、すべてのワーカー (ゴルーチン) がタスクの実行を完了するのを待ちます。次に、実行するタスクをジョブ チャネルに送信し、実行後にチャネルを閉じます。最後に、結果チャネルから計算結果を取得して出力します。

3. WaitGroup とコルーチン プールの効率的な組み合わせケース
次に、上記 2 つの概念を組み合わせて、WaitGroup とコルーチン プールを効果的に使用して同時プログラミングを実装する方法を紹介します。具体的なサンプル コードは次のとおりです。

package main

import (
    "fmt"
    "sync"
)

func worker(id int, jobs <-chan int, results chan<- int) {
    for j := range jobs {
        fmt.Println("Worker", id, "started job", j)
        fib := fibonacci(j)
        fmt.Println("Worker", id, "finished job", j)
        results <- fib
    }
}

func fibonacci(n int) int {
    if n <= 1 {
        return n
    }

    return fibonacci(n-1) + fibonacci(n-2)
}

const numJobs = 5
const numWorkers = 3

func main() {
    var wg sync.WaitGroup
    wg.Add(numWorkers)

    jobs := make(chan int, numJobs)
    results := make(chan int, numJobs)

    for w := 1; w <= numWorkers; w++ {
        go func(id int) {
            defer wg.Done()
            worker(id, jobs, results)
        }(w)
    }

    for j := 1; j <= numJobs; j++ {
        jobs <- j
    }
    close(jobs)

    go func() {
        wg.Wait()
        close(results)
    }()

    for r := range results {
        fmt.Println(r)
    }
}

上の例では、WaitGroup オブジェクトを作成し、Add メソッドを呼び出してカウンターをインクリメントしました。次に、タスクを分散して結果を取得するために、ジョブ チャネルと結果チャネルを作成しました。固定数のワーカー (ゴルーチン) を作成し、Wait メソッドを使用してワーカーがタスクを完了するのを待ちます。

main 関数では、実行するタスクをジョブ チャネルに送信し、完了後にチャネルを閉じます。次に、すべてのワーカーがタスクを完了するのを待機するコルーチンを開始し、完了したら結果チャネルを閉じます。最後に、結果チャネルから計算結果を取得して出力します。

結論:
WaitGroup とコルーチン プールを組み合わせることで、効率的に並行プログラミングを実装できます。 WaitGroup を使用してゴルーチンのグループの実行が完了するのを待つことにより、すべてのタスクが完了した後もメインのゴルーチンが確実に実行し続けるようにすることができます。コルーチン プールを使用すると、頻繁にゴルーチンを作成および破棄するオーバーヘッドを回避し、プログラムの実行効率とリソース使用率を向上させることができます。

コード例のフィボナッチ数列計算は単なるデモンストレーション例であり、実際のアプリケーションの特定のニーズに応じて他のタスクに置き換えることができます。 WaitGroup とコルーチン プールを使用すると、同時に実行されるタスクの数をより適切に制御し、コンピューティング リソースを効果的に利用できます。

Go 言語には豊富な同時プログラミング ツールと機能が用意されていますが、それらを使用する場合は注意が必要です。 WaitGroup とコルーチン プールを適切に使用すると、ゴルーチンの管理とスケジュールを改善し、効率的な同時プログラミングを実現できます。

以上がGolang WaitGroup とコルーチン プールの効率的な組み合わせの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。