目次
質問内容
解決策
より良いアプローチ: nil可能なチャネルを選択に使用します
ホームページ バックエンド開発 Golang 3 番目のゴルーチン内の 2 つのゴルーチンの完了ステータスを追跡するための Golang のベスト プラクティスは何ですか?

3 番目のゴルーチン内の 2 つのゴルーチンの完了ステータスを追跡するための Golang のベスト プラクティスは何ですか?

Feb 11, 2024 pm 02:54 PM
overflow

Golang 中跟踪第三个 Goroutine 中两个 Goroutine 的完成状态的最佳实践是什么?

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 に設定します。selectnil# からは決して成功しません。 ## チャネルはコンテンツを読み取るため、これにより事実上選択が「無効」になります。

コードの修正バージョン : を考えてみましょう。 リーリー

コンシューマーに対するこれらの調整により、ホット ループはなくなり、データがチャネルから読み取られるまで常にブロックされます。

salesDonepurchasesDone の両方が「通知」されると、close(transactions) になります。 transactions を使い果たし、 がクローズされると、transactions を nil に設定します。 transactions が nil でない場合にループします。このコードでは、すべてのチャネルが nil であることを意味します。

微妙だが重要な点: この関数にチャネルを渡しているので、その参照は

main とスコープを共有しません。それ以外の場合、transactionsnil に設定すると、ゴルーチン間で共有される変数に書き込まれます。ただし、この場合は、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 多个通道简单得多。事实上,我什至想说,如果您发现自己从多个渠道进行 selecting,您应该退后一步,确保它对您来说确实有意义。我使用 select 的频率远远低于使用等待组的频率。

以上が3 番目のゴルーチン内の 2 つのゴルーチンの完了ステータスを追跡するための Golang のベスト プラクティスは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

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

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

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

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

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

2009 年から 2025 年の誕生以来のビットコインの価格 BTC 過去の価格の最も完全な概要 2009 年から 2025 年の誕生以来のビットコインの価格 BTC 過去の価格の最も完全な概要 Jan 15, 2025 pm 08:11 PM

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

ビットコインの誕生以来の歴史的な価格の概要。ビットコインの歴史的な価格動向を完全にまとめています。 ビットコインの誕生以来の歴史的な価格の概要。ビットコインの歴史的な価格動向を完全にまとめています。 Jan 15, 2025 pm 08:14 PM

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

ビットコインBTC歴史的価格動向チャートの誕生以来の歴史的価格のリスト(最新の要約) ビットコインBTC歴史的価格動向チャートの誕生以来の歴史的価格のリスト(最新の要約) Feb 11, 2025 pm 11:36 PM

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

2018-2024 USDのビットコインの最新価格 2018-2024 USDのビットコインの最新価格 Feb 15, 2025 pm 07:12 PM

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

ビットコインの誕生以来の歴史的価格の詳細の最も完全な要約(2025年の最新バージョン) ビットコインの誕生以来の歴史的価格の詳細の最も完全な要約(2025年の最新バージョン) Feb 15, 2025 pm 06:45 PM

ビットコインの重要なノード履歴価格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コミュニティは課題にどのように対応できますか? ChatGpt時代には、技術的なQ&Aコミュニティは課題にどのように対応できますか? Apr 01, 2025 pm 11:51 PM

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

1つの記事で、次のことをご覧ください:仮想通貨基金レートとは何ですか? 1つの記事で、次のことをご覧ください:仮想通貨基金レートとは何ですか? Feb 15, 2025 pm 10:06 PM

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

CSSのクリップパス属性を使用して、セグメルターの45度曲線効果を実現する方法は? CSSのクリップパス属性を使用して、セグメルターの45度曲線効果を実現する方法は? Apr 04, 2025 pm 11:45 PM

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

See all articles