ホームページ > バックエンド開発 > Golang > Go のジェネレーター同時実行パターン: 包括的なガイド

Go のジェネレーター同時実行パターン: 包括的なガイド

Mary-Kate Olsen
リリース: 2025-01-04 06:16:40
オリジナル
293 人が閲覧しました

⚠️ このシリーズをどのように進めていきますか?

1.すべての例を実行: コードを読むだけではありません。入力して実行し、動作を観察してください。
2.実験と破壊: スリープを削除して何が起こるか確認し、チャネル バッファー サイズを変更し、ゴルーチン数を変更します。
物を壊すことで、その仕組みがわかる
3.動作に関する理由: 変更されたコードを実行する前に、結果を予測してみてください。予期せぬ動作が見られた場合は、立ち止まってその理由を考えてください。解説に挑戦してください。
4.メンタル モデルの構築: 各ビジュアライゼーションはコンセプトを表します。変更されたコード用に独自の図を描いてみてください。

Generator Concurrency Pattern in Go: A Comprehensive Guide

前回の投稿では、Go の並行性の構成要素であるゴルーチンとチャネルの基本について説明しました。ここをお読みください:

Generator Concurrency Pattern in Go: A Comprehensive Guide

Golang でのゴルーチンとチャネルの理解と視覚化

スーヴィク・カル・マハパトラ・12月20日

#行く #プログラミング #学ぶ #チュートリアル

ここで、これらのプリミティブがどのように組み合わされて、現実世界の問題を解決する強力なパターンを形成するかを見てみましょう。

この投稿では、ジェネレーター パターン について説明し、視覚化してみます。プロセス全体を通じて実際に作業を進めていきますので、準備を整えましょう。

Generator Concurrency Pattern in Go: A Comprehensive Guide

ジェネレーターパターン

ジェネレーターは、必要なときにいつでも消費できる価値を継続的に生成する噴水のようなものです。

Go では、これは値のストリームを生成し、チャネルを通じて送信する関数であり、プログラムの他の部分がこれらの値をオンデマンドで受信できるようにします。

Generator Concurrency Pattern in Go: A Comprehensive Guide

例を見てみましょう:

// generateNumbers creates a generator that produces numbers from 1 to max
func generateNumbers(max int) chan int {
    // Create a channel to send numbers
    out := make(chan int)

    // Launch a goroutine to generate numbers
    go func() {
        // Important: Always close the channel when done
        defer close(out)

        for i := 1; i <= max; i++ {
            out <- i  // Send number to channel
        }
    }()

    // Return channel immediately
    return out
}

// Using the generator
func main() {
    // Create a generator that produces numbers 1-5
    numbers := generateNumbers(5)

    // Receive values from the generator
    for num := range numbers {
        fmt.Println("Received:", num)
    }
}
ログイン後にコピー
ログイン後にコピー

この例では、ジェネレーター関数は 3 つの重要なことを実行します。

  1. 値を送信するチャネルを作成します
  2. 値を生成するゴルーチンを起動します
  3. 消費者が使用できるチャネルをすぐに返します

ジェネレーターを使用する理由

  1. 価値の生産と消費を分離する
  2. オンデマンドで値を生成 (遅延評価)
  3. 無限のメモリを消費せずに無限のシーケンスを表現できます
  4. 値の同時生成と消費を許可します

実際の使用例

大きなファイルを 1 行ずつ読み取る:

func generateLines(filename string) chan string {
    out := make(chan string)
    go func() {
        defer close(out)
        file, err := os.Open(filename)
        if err != nil {
            return
        }
        defer file.Close()

        scanner := bufio.NewScanner(file)
        for scanner.Scan() {
            out <- scanner.Text()
        }
    }()
    return out
}
ログイン後にコピー
ログイン後にコピー

ここで、何がそんなに特別なの?と考えているかもしれません。データのシーケンスを生成したり、ゴルーチン を使用せずに 1 行ずつ読み取るのと同じことを行うことができます。やりすぎじゃないですか?両方のケースを視覚化してみましょう:

ゴルーチンなし

// Traditional approach
func getNumbers(max int) []int {
    numbers := make([]int, max)
    for i := 1; i <= max; i++ {
        numbers[i-1] = i
        // Imagine some heavy computation here
        time.Sleep(100 * time.Millisecond)
    }
    return numbers
}
ログイン後にコピー
ログイン後にコピー

ここでは、処理を開始する前に、すべての準備が整うまで待つ必要があります。

ゴルーチンを使用する

// Generator approach
func generateNumbers(max int) chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for i := 1; i <= max; i++ {
            out <- i
            // Same heavy computation
            time.Sleep(100 * time.Millisecond)
        }
    }()
    return out
}
ログイン後にコピー
ログイン後にコピー

データの生成中にデータの処理を開始できます。

Generator Concurrency Pattern in Go: A Comprehensive Guide

ジェネレーター パターンの主な利点:

  1. ノンブロッキング実行: 生成と処理は同時に行われます

  2. メモリ効率: 一度に 1 つの値を生成して処理できるため、すぐにメモリに保存する必要はありません

  3. 無限シーケンス: メモリの問題なく無限シーケンスを生成できます

  4. バックプレッシャー処理: コンシューマが遅い場合、ジェネレータは自然に (チャネル ブロックにより) 速度を落とし、メモリの過負荷を防ぎます。

// generateNumbers creates a generator that produces numbers from 1 to max
func generateNumbers(max int) chan int {
    // Create a channel to send numbers
    out := make(chan int)

    // Launch a goroutine to generate numbers
    go func() {
        // Important: Always close the channel when done
        defer close(out)

        for i := 1; i <= max; i++ {
            out <- i  // Send number to channel
        }
    }()

    // Return channel immediately
    return out
}

// Using the generator
func main() {
    // Create a generator that produces numbers 1-5
    numbers := generateNumbers(5)

    // Receive values from the generator
    for num := range numbers {
        fmt.Println("Received:", num)
    }
}
ログイン後にコピー
ログイン後にコピー

よくある落とし穴と解決策

  1. チャンネルを閉じ忘れる
func generateLines(filename string) chan string {
    out := make(chan string)
    go func() {
        defer close(out)
        file, err := os.Open(filename)
        if err != nil {
            return
        }
        defer file.Close()

        scanner := bufio.NewScanner(file)
        for scanner.Scan() {
            out <- scanner.Text()
        }
    }()
    return out
}
ログイン後にコピー
ログイン後にコピー
  1. エラーを処理しない
// Traditional approach
func getNumbers(max int) []int {
    numbers := make([]int, max)
    for i := 1; i <= max; i++ {
        numbers[i-1] = i
        // Imagine some heavy computation here
        time.Sleep(100 * time.Millisecond)
    }
    return numbers
}
ログイン後にコピー
ログイン後にコピー
  1. リソース リーク: リソース (ファイルなど) でジェネレーターを使用する場合は、適切なクリーンアップを確認してください。
// Generator approach
func generateNumbers(max int) chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for i := 1; i <= max; i++ {
            out <- i
            // Same heavy computation
            time.Sleep(100 * time.Millisecond)
        }
    }()
    return out
}
ログイン後にコピー
ログイン後にコピー

ジェネレータ パターンについては以上です。次は パイプライン同時実行パターン です。 Golang の同時実行性に関する概念を明確にするために、ご期待ください。

何か見逃したでしょうか?質問がありますか?何か面白いことを共有したいですか?すべてのコメントを歓迎します。

以上がGo のジェネレーター同時実行パターン: 包括的なガイドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート