0Pricing
Go Academy · レッスン

Fan-OutとFan-In

処理を分散して収集します

「Fan-OutとFan-In」はCoddyKit上の無料Go Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはGo Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Go Academyコースには全4レッスンが含まれています。

ファンアウトとファンイン

ファンアウトとは、複数の goroutine を起動して1つのチャネルから読み取り、処理を分散することです。ファンインとは、複数の goroutine の出力を1つのチャネルにまとめることです。

  • ファンアウトによってワーカー間に負荷を分散します
  • ファンインによってコンシューマー向けに結果を集約します

ジェネレーターステージ

パイプラインはジェネレーターから始まります。ジェネレーターはチャネルを返す関数で、自身の goroutine からそのチャネルに値を送り、その後チャネルを閉じます。

func gen(nums ...int) <-chan int {
    out := make(chan int)
    go func() {
        for _, n := range nums {
            out <- n
        }
        close(out)
    }()
    return out
}

ファンアウト

ファンアウトするには、同じ入力チャネルから読み取る複数の goroutine を起動します。それぞれが同じ処理関数を実行し、独自の出力チャネルを生成します。

in := gen(1, 2, 3, 4, 5)
c1 := square(in)
c2 := square(in)

処理ステージ

square ステージは in から読み取り、各値を二乗して、新しい出力チャネルに送信します。このステージの複数のインスタンスで1つの入力を共有できます。

func square(in <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        for n := range in {
            out <- n * n
        }
        close(out)
    }()
    return out
}

merge によるファンイン

ファンインでは複数のチャネルを1つにまとめます。sync.WaitGroup でチャネルごとの goroutine を追跡し、終了用の goroutine はすべての goroutine が完了してから、統合した出力を閉じます。

func merge(cs ...<-chan int) <-chan int {
    out := make(chan int)
    var wg sync.WaitGroup
    for _, c := range cs {
        wg.Add(1)
        go func(c <-chan int) {
            for n := range c {
                out <- n
            }
            wg.Done()
        }(c)
    }
    go func() { wg.Wait(); close(out) }()
    return out
}

WaitGroup を使う理由

統合用の各 goroutine は、1つの入力チャネルから out へ値をコピーします。すべての入力を読み終えるまで、out を閉じてはいけません。WaitGroup はアクティブなコピー処理の数を数え、終了用の goroutine はそれらが完了するまで wg.Wait() でブロックします。

ループ変数のキャプチャ

古い Go では、各 goroutine が共有されたループ変数ではなく、それぞれのチャネルを束縛するように、クロージャーが c をパラメーターとして受け取る必要があります。c を明示的に渡すことで、典型的なループ変数のバグを回避できます。

完全なファンアウトとファンイン

このプログラムは数値を生成し、2つの square ステージにファンアウトしてから、ファンインして統合した結果を合計します。

package main

import (
    "fmt"
    "sync"
)

func gen(nums ...int) <-chan int {
    out := make(chan int)
    go func() { for _, n := range nums { out <- n }; close(out) }()
    return out
}

func square(in <-chan int) <-chan int {
    out := make(chan int)
    go func() { for n := range in { out <- n * n }; close(out) }()
    return out
}

func merge(cs ...<-chan int) <-chan int {
    out := make(chan int)
    var wg sync.WaitGroup
    for _, c := range cs {
        wg.Add(1)
        go func(c <-chan int) { for n := range c { out <- n }; wg.Done() }(c)
    }
    go func() { wg.Wait(); close(out) }()
    return out
}

func main() {
    in := gen(1, 2, 3, 4, 5)
    c1 := square(in)
    c2 := square(in)
    total := 0
    for n := range merge(c1, c2) {
        total += n
    }
    fmt.Println("sum of squares:", total)
}

順序は保証されません

2つの square ステージが同じ入力を取り合うため、統合後の出力順序は非決定的です。順序が必要な場合は、各項目にインデックスを付けるか、ステージを1つにしてください。

ファンアウトするタイミング

あるステージがボトルネックで、処理を並列化できる場合にファンアウトします。上流のジェネレーターが遅い場合は、下流のワーカーを増やしても効果はありません。ワーカーが待機するだけになります。

バックプレッシャー

バッファーなしチャネルは自然なバックプレッシャーを生みます。遅いコンシューマーが処理しきれないと、速いステージはブロックします。これにより、パイプライン全体でメモリが際限なく増加するのを防ぎます。

クイックチェック

ファンインについての理解度を確認しましょう。

まとめ

ファンアウトとファンインについて学びました。

  • ファンアウト:複数の goroutine で1つのチャネルから読み取ります
  • ファンイン:WaitGroup を使って複数のチャネルを1つにまとめます
  • 並列ステージ間では順序は維持されません
  • バッファーなしチャネルはバックプレッシャーを提供します

よくある質問

「Fan-OutとFan-In」レッスンは無料ですか?

はい。「Fan-OutとFan-In」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Go Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Go Academyコースには全4レッスンが含まれています。

「Fan-OutとFan-In」で何を学びますか?

処理を分散して収集します ブラウザで直接実行するハンズオンコードでGo Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Go Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのGo Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「Fan-OutとFan-In」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このGo Academyレッスンでコードを書いて実行できますか?

はい。すべてのGo Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. ワーカープールパターン
  2. Fan-OutとFan-In
  3. パイプラインのステージ
  4. グレースフルシャットダウン
← Go Academyに戻る