3 番目のゴルーチン内の 2 つのゴルーチンの完了ステータスを追跡するための Golang のベスト プラクティスは何ですか?
Golang で 3 番目の Goroutine で 2 つの Goroutine の完了ステータスを追跡するためのベスト プラクティスは何ですか? Golang では、2 つのゴルーチンの完了ステータスを追跡し、その結果を 3 番目のゴルーチンで処理するには、同期パッケージの WaitGroup を使用するのがベスト プラクティスです。 WaitGroup を使用すると、メインの Goroutine で他の Goroutine の完了を待つことができます。まず、WaitGroup オブジェクトを作成し、メインの Goroutine で Add メソッドを呼び出して待機中の Goroutine の数を設定する必要があります。次に、各ゴルーチンの最後に Done メソッドが呼び出され、そのゴルーチンの完了を通知します。最後に、3 番目のゴルーチンで Wait メソッドが呼び出され、すべてのゴルーチンが完了するまで待機します。こうすることで、両方のゴルーチンの結果を安全に追跡して処理できます。これは、複数の Goroutine の完了ステータスを追跡するための Golang のベスト プラクティスです。
質問内容
3つのゴルーチンを同時に実行しています。そのうちの 2 つは何らかの処理を実行し、結果を結果チャネルに送信します。 3 番目のゴルーチンは、結果チャネルを読み取ることによって結果を「カウント」します。 waitgroup を使用して 2 つの計算ゴルーチンが完了するのを待ってから、結果チャネルを反復処理して結果を集計することもできますが、これでは拡張できず、巨大なバッファ サイズでバッファリングされた結果チャネルを作成する必要があり、これは受け入れられません。プロダクションコードで。
処理の実行中に結果をカウントしたいのですが、すべての統計が完了する前にプログラムを終了したくありません。 Go でこれを達成するためのベスト プラクティスは何ですか?
これは私の現在の方法であり、うまく機能します。これは少し不格好に見えるので、より良い方法があるかどうか疑問に思っていますか?
package main import ( "fmt" "sync" ) type T struct{} func main() { var widgetInventory int = 1000 transactions := make(chan int, 100) salesDone := make(chan T) purchasesDone := make(chan T) var wg sync.WaitGroup fmt.Println("Starting inventory count = ", widgetInventory) go makeSales(transactions, salesDone) go newPurchases(transactions, purchasesDone) wg.Add(1) go func() { salesAreDone := false purchasesAreDone := false for { select { case transaction := <-transactions: widgetInventory += transaction case <-salesDone: salesAreDone = true case <-purchasesDone: purchasesAreDone = true default: if salesAreDone && purchasesAreDone { wg.Done() return } } } }() wg.Wait() fmt.Println("Ending inventory count = ", widgetInventory) } func makeSales(transactions chan int, salesDone chan T) { for i := 0; i < 3000; i++ { transactions <- -100 } salesDone <- struct{}{} } func newPurchases(transactions chan int, purchasesDone chan T) { for i := 0; i < 3000; i++ { transactions <- 100 } purchasesDone <- struct{}{} }
解決策
適切な定義に適合しません良い。ここにホット for
ループがあります:
読み取り元のチャネルがない限り、default
ケースが実行されます。これは、チャネルの仕組みが原因で頻繁に発生します。
コードのこのわずかに調整されたバージョンは、このループの「熱さ」を示しています。 正確な結果はさまざまであり、かなり高い値になる可能性があります。
リーリーデフォルトで何かがブロックされていない限り、チャネルから select
するときに default
の状況は望ましくありません。そうしないと、このような熱サイクルが発生します。
より良いアプローチ: nil
可能なチャネルを選択に使用します
通常、選択では閉じたチャネルを特定し、チャネル変数を nil
に設定します。select
は nil# からは決して成功しません。 ## チャネルはコンテンツを読み取るため、これにより事実上選択が「無効」になります。
コードの修正バージョン : を考えてみましょう。 リーリー
コンシューマーに対するこれらの調整により、ホット ループはなくなり、データがチャネルから読み取られるまで常にブロックされます。salesDone と
purchasesDone の両方が「通知」されると、
close(transactions) になります。
transactions
を使い果たし、 がクローズされると、transactions を nil に設定します。
transactions が nil でない場合にループします。このコードでは、すべてのチャネルが
nil であることを意味します。
main とスコープを共有しません。それ以外の場合、
transactions を
nil に設定すると、ゴルーチン間で共有される変数に書き込まれます。ただし、この場合は、
transactions から最後に読み取ることが「わかっている」ため、それは問題ではありません。
ここで何をしているのかを考えると、両方のプロデューサーが
トランザクション の生成を完了するまで待つ必要があります。次に、
transactions を排出します。チャネルが閉じられて排出されると、
main は合計が完了したことを認識します。
select は必要ありません。そして、
select が各 "ワーカー" にケースを持たせるのは、おそらくかなり洗練されていないため、複数のワーカーをハードコーディングし、"完了" チャネルを個別に処理する必要があります。
- 除了为生产者使用一个
var resultswgsync.WaitGroup
之外,还为消费者添加一个。 - 生产者
defer wg.Done()
- 消费者
defer resultswg.Done()
在遍历transactions
之前:go func() { defer resultswg.Done() for transaction := range transactions { widgetInventory += transaction } }()
ログイン後にコピー - main 处理等待生产者、关闭事务以结束范围,然后等待消费者:
wg.Wait() close(transactions) resultswg.Wait()
ログイン後にコピー
package main import ( "fmt" "sync" ) func main() { var widgetInventory int = 1000 transactions := make(chan int, 100) var wg, resultswg sync.WaitGroup fmt.Println("Starting inventory count = ", widgetInventory) wg.Add(2) go makeSales(transactions, &wg) go newPurchases(transactions, &wg) resultswg.Add(1) go func() { defer resultswg.Done() for transaction := range transactions { widgetInventory += transaction } }() wg.Wait() close(transactions) resultswg.Wait() fmt.Println("Ending inventory count = ", widgetInventory) } func makeSales(transactions chan int, wg *sync.WaitGroup) { defer wg.Done() for i := 0; i < 3000; i++ { transactions <- -100 } } func newPurchases(transactions chan int, wg *sync.WaitGroup) { defer wg.Done() for i := 0; i < 3000; i++ { transactions <- 100 } }
您可以在这里看到,在此模式中可以有任意数量的生产者;您只需为每个生产者添加 wg.Add(1)
即可。
当我不知道每个工作人员会返回多少结果时,我一直使用这种模式来并行化工作。我发现它很容易理解,并且比尝试 select
多个通道简单得多。事实上,我什至想说,如果您发现自己从多个渠道进行 select
ing,您应该退后一步,确保它对您来说确实有意义。我使用 select
的频率远远低于使用等待组的频率。
以上が3 番目のゴルーチン内の 2 つのゴルーチンの完了ステータスを追跡するための Golang のベスト プラクティスは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

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

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

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

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

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

ホットトピック

2009 年の誕生以来、ビットコインは暗号通貨の世界のリーダーとなり、その価格は大きな変動を経験しました。包括的な歴史的概要を提供するために、この記事では 2009 年から 2025 年までのビットコイン価格データをまとめ、主要な市場イベント、市場センチメントの変化、価格変動に影響を与える重要な要因を取り上げます。

暗号通貨としてのビットコインは、その誕生以来、市場の大きな変動を経験してきました。この記事では、読者がビットコインの価格傾向と重要な瞬間を理解できるように、誕生以来のビットコインの歴史的な価格の概要を提供します。ビットコインの過去の価格データを分析することで、その価値に対する市場の評価やその変動に影響を与える要因を理解し、将来の投資決定の基礎を提供することができます。

2009年の作成以来、ビットコインの価格はいくつかの大きな変動を経験し、2021年11月に69,044.77ドルに上昇し、2018年12月に3,191.22ドルに減少しました。 2024年12月の時点で、最新の価格は100,204ドルを超えています。

リアルタイムのビットコインUSD価格 ビットコインの価格に影響を与える要因 将来のビットコイン価格を予測するための指標 2018年から2024年のビットコインの価格に関する重要な情報を次に示します。

ビットコインの重要なノード履歴価格2009年1月3日:ジェネシスブロックが生成され、最初のビットコインが生成され、値0の値が生成されました。 10月5日:最初のビットコイントランザクション、プログラマーが10,000ドルのビットコインを備えた2つのピザを購入しました。これは0.008ドルに相当します。 2010年2月9日:Gox Moux Exchangeはオンラインになり、初期のビットコイン取引の主要なプラットフォームになりました。 5月22日:ビットコインは初めて1ドルを破ります。 7月17日:ビットコインプライスは0.008ドルに急落し、史上最低値に達しました。 2011年2月9日:ビットコインの価格は初めて10ドルを破ります。 4月10日:Mt。Go

ChatGpt時代のテクニカルQ&Aコミュニティ:SegmentFaultの対応戦略StackOverFlow ...

仮想通貨の資金調達率は、デリバティブ取引でポジションを保持しているトレーダーに請求される手数料です。これは、契約の有効期限が切れたときのスポット市場価格と先物契約価格との間のプレミアムまたは割引を反映しています。スポット価格が先物価格よりも高い場合、資本金利はマイナスです。つまり、ショートポジションが長いポジションのトレーダーに手数料を支払うトレーダーは意味があります。それどころか、スポット価格が先物価格よりも低い場合、資本金利はプラスです。つまり、長いポジションを行うトレーダーは、ショートポジションを行うトレーダーに料金を支払うことです。

セグメントターの45度の曲線効果を達成する方法は?セグメンテーションデバイスを実装する過程で、左ボタンをクリックすると、適切な境界線を45度の曲線に変える方法とポイント...
