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

Go のジェネレーター同時実行パターン: ビジュアル ガイド
スーヴィク・カル・マハパトラ・12月25日
ここで、これらのプリミティブがどのように組み合わされて、現実世界の問題を解決する強力なパターンを形成するかを見てみましょう。
この投稿では、パイプライン パターン について説明し、視覚化してみます。プロセス全体を通じて実際に作業を進めていきますので、準備を整えましょう。
パイプラインパターン
パイプラインは工場の組立ラインに似ており、各ステージがデータに対して特定のタスクを実行し、結果を次のステージに渡します。
ゴルーチンをチャネルに接続することでパイプラインを構築します。各ゴルーチンは、データを受信し、処理し、次のステージに送信するステージを表します。
次のような単純なパイプラインを実装してみましょう。
- 数値を生成します
- 二乗します
- 結果を印刷します
// Stage 1: Generate numbers func generate(nums ...int) <-chan int { out := make(chan int) go func() { defer close(out) for _, n := range nums { out <- n } }() return out } // Stage 2: Square numbers func square(in <-chan int) <-chan int { out := make(chan int) go func() { defer close(out) for n := range in { out <- n * n } }() return out } // Stage 3: Print numbers func print(in <-chan int) { for n := range in { fmt.Printf("%d ", n) } fmt.Println() } func main() { // Connect the pipeline numbers := generate(2, 3, 4) // Stage 1 squares := square(numbers) // Stage 2 print(squares) // Stage 3 }
✏️クイックバイト
<-chan int は受信専用チャネルを示します。
<-chan int 型のチャネルは、値を送信するのではなく、値を受信するためにのみ使用できます。これは、より厳格な通信パターンを適用し、受信者によるチャネルへの誤った書き込みを防ぐのに役立ちます。chan int これは双方向チャネルを示します。
chan int 型のチャネルは、値の送信と受信の両方に使用できます。
上記の例を視覚化してみましょう:
ここでは、パイプラインの各構成要素がジェネレーター パターンに従ったゴルーチンであることがわかります。順次処理とは異なり、いずれかのステップでデータの準備が整うとすぐに、パイプラインの次のステップでデータの処理を開始できることを意味します。
パイプラインでのエラー処理
核となる原則は次のとおりです:
- 各ステージは、良い値と悪い値の両方をどうすべきかを正確に知っています
- エラーがパイプラインで失われることはありません
- 間違った値はパニックを引き起こしません
- エラー メッセージには、問題の内容が記載されています
- パイプラインはステージを増やして拡張でき、すべてのステージで一貫してエラーが処理されます
適切なエラー処理を追加してコードを更新しましょう。
type Result struct { Value int Err error } func generateWithError(nums ...int) <-chan Result { out := make(chan Result) go func() { defer close(out) for _, n := range nums { if n < 0 { out <- Result{Err: fmt.Errorf("negative number: %d", n)} return } out <- Result{Value: n} } }() return out } func squareWithError(in <-chan Result) <-chan Result { out := make(chan Result) go func() { defer close(out) for r := range in { if r.Err != nil { out <- r // Forward the error continue } out <- Result{Value: r.Value * r.Value} } }() return out } func main() { // Using pipeline with error handling for result := range squareWithError(generateWithError(2, -3, 4)) { if result.Err != nil { fmt.Printf("Error: %v\n", result.Err) continue } fmt.Printf("Result: %d\n", result.Value) } }
パイプライン パターンを使用する理由
理解を深めるために例を挙げてみましょう。以下に示すようなパイプライン パターンに従うデータ処理ワークフローがあります。
- パイプラインの各ステージは独立して動作し、チャネルを通じてのみ通信します。これにより、次のようないくつかの利点が得られます。
?各段階は個別に開発、テスト、変更できます
? 1 つのステージの内部を変更しても、他のステージには影響しません
?新しいステージの追加や既存のステージの変更が簡単
?懸念事項を明確に分離
- パイプライン パターンにより、並列/同時処理が自然に可能になります。データが利用可能になるとすぐに、各ステージで異なるデータを同時に処理できます。
そして一番いいところは?次のように、より多くの同時要件に対して各ステージ (ワーカー) の複数のインスタンスを実行できます。
??あれ、でもそれは ファンインおよびファンアウトの同時実行パターン ではないですか?
ビンゴ!そこに良いキャッチがあります。これは確かにファンアウト、ファンイン パターンであり、特定のタイプのパイプライン パターンです。次の投稿で詳しく説明するので、心配しないでください ;)
現実世界の使用例
パイプラインで画像を処理しています
// Stage 1: Generate numbers func generate(nums ...int) <-chan int { out := make(chan int) go func() { defer close(out) for _, n := range nums { out <- n } }() return out } // Stage 2: Square numbers func square(in <-chan int) <-chan int { out := make(chan int) go func() { defer close(out) for n := range in { out <- n * n } }() return out } // Stage 3: Print numbers func print(in <-chan int) { for n := range in { fmt.Printf("%d ", n) } fmt.Println() } func main() { // Connect the pipeline numbers := generate(2, 3, 4) // Stage 1 squares := square(numbers) // Stage 2 print(squares) // Stage 3 }
またはログ処理パイプラインのような複雑なもの
パイプラインのスケーリング パターン
水平スケーリング (ファンアウト、ファンイン)
このパターンは、作業を独立して処理できる CPU 依存の操作に最適です。パイプラインは複数のワーカーに作業を分散し、結果を再結合します。これは、次の場合に特に効果的です。
- 処理は CPU を集中的に使用します (データ変換、計算)
- タスクは独立して処理できます
- 複数の CPU コアが使用可能です
バッファされたパイプライン
このパターンは、パイプライン ステージ間の速度の不一致を管理するのに役立ちます。バッファーはショックアブソーバーとして機能し、遅いステージによってブロックされることなく、高速なステージが先に動作できるようにします。これは次の場合に役立ちます。
- ステージが異なると処理速度も異なります
- 安定したスループットを維持したい
- バッファリングのためのメモリ使用量は許容されます
- バースト処理を処理する必要があります
バッチ処理
このパターンは、複数の項目を 1 つのバッチにグループ化することで、I/O バウンド操作を最適化します。項目を一度に 1 つずつ処理するのではなく、項目をグループにまとめて一緒に処理します。これは次の場合に効果的です。
- 外部システム (データベース、API) を使用している
- ネットワークの往復は高価です
- この操作にはリクエストごとに大幅な固定オーバーヘッドがあります
- レイテンシよりもスループットを最適化する必要があります
これらの各パターンは、必要に応じて組み合わせることができます。たとえば、複数のワーカーがそれぞれアイテムのバッチを処理する、水平スケーリングを備えたバッチ処理を使用できます。 重要なのは、ボトルネックを理解し、それに対処するための適切なパターンを選択することです。
これで、ジェネレーター パターンについての詳細な説明は終わりです。次に、パイプライン同時実行パターンを検討し、ジェネレーターをチェーンして強力なデータ処理フローを構築する方法を見ていきます。
この投稿が役に立ったと思われた場合、ご質問がある場合、またはジェネレーターに関するご自身の経験を共有したい場合は、以下のコメント欄からご意見をお待ちしております。皆様の洞察や質問は、これらの説明を誰にとってもさらにわかりやすくするのに役立ちます。
Golang のゴルーチンとチャネルのビジュアルガイドを見逃した場合は、ここで確認してください:

Golang でのゴルーチンとチャネルの理解と視覚化
スーヴィク・カル・マハパトラ・12月20日
Go の同時実行パターンについては今後も続報をお待ちください! ?
以上がGo のパイプライン同時実行パターン: 包括的なビジュアル ガイドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











OpenSSLは、安全な通信で広く使用されているオープンソースライブラリとして、暗号化アルゴリズム、キー、証明書管理機能を提供します。ただし、その歴史的バージョンにはいくつかの既知のセキュリティの脆弱性があり、その一部は非常に有害です。この記事では、Debian SystemsのOpenSSLの共通の脆弱性と対応測定に焦点を当てます。 Debianopensslの既知の脆弱性:OpenSSLは、次のようないくつかの深刻な脆弱性を経験しています。攻撃者は、この脆弱性を、暗号化キーなどを含む、サーバー上の不正な読み取りの敏感な情報に使用できます。

Beegoormフレームワークでは、モデルに関連付けられているデータベースを指定する方法は?多くのBEEGOプロジェクトでは、複数のデータベースを同時に操作する必要があります。 Beegoを使用する場合...

バックエンド学習パス:フロントエンドからバックエンドへの探査の旅は、フロントエンド開発から変わるバックエンド初心者として、すでにNodeJSの基盤を持っています...

Golandのカスタム構造ラベルが表示されない場合はどうすればよいですか?ゴーランドを使用するためにGolandを使用する場合、多くの開発者はカスタム構造タグに遭遇します...

redisstreamを使用してGo言語でメッセージキューを実装する問題は、GO言語とRedisを使用することです...

Go Crawler Collyのキュースレッドの問題は、Go言語でColly Crawler Libraryを使用する問題を調査します。 �...

Go言語での文字列印刷の違い:printlnとstring()関数を使用する効果の違いはGOにあります...
