62

ここで以前の質問を読みましたConcurrentBagが、マルチスレッドでの実装の実際のサンプルは見つかりませんでした。

ConcurrentBag はスレッド セーフなバッグ実装であり、同じスレッドがバッグに格納されたデータの生成と消費の両方を行うシナリオ向けに最適化されています。」

現在、これは私のコードでの現在の使用法です(これは実際のコードではなく単純化されています):

private void MyMethod()
{
    List<Product> products = GetAllProducts(); // Get list of products
    ConcurrentBag<Product> myBag = new ConcurrentBag<Product>();

    //products were simply added here in the ConcurrentBag to simplify the code
    //actual code process each product before adding in the bag
    Parallel.ForEach(
                products,
                new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
                product => myBag.Add(product));

    ProcessBag(myBag); // method to process each items in the concurrentbag
}

私の質問:
これは の正しい使い方ConcurrentBagですか? ConcurrentBagこんなシーンで使っていいの?

私にとっては、単純なList<Product>手動ロックの方がうまくいくと思います。この理由は、上記のシナリオが既に「同じスレッドがバッグに格納されたデータの生成と消費の両方を行う」という規則に違反しているためです。
またThreadLocal、並列の各スレッドで作成されたストレージは、操作後も (スレッドが再利用されたとしても) まだ存在し、望ましくないメモリ リークが発生する可能性があることもわかりました。
私はこれで正しいですか?または、単純な clear または empty メソッドでアイテムを削除するConcurrentBagだけで十分ですか?

4

3 に答える 3

27

これは、ConcurrentBag の正しい使い方のようです。スレッド ローカル変数はバッグのメンバーであり、バッグと同時にガベージ コレクションの対象になります (内容をクリアしても解放されません)。あなたの場合、ロック付きの単純なリストで十分であることは間違いありません。ループ内で実行している作業が重要な場合、スレッド同期のタイプは全体的なパフォーマンスにはあまり影響しません。その場合、使い慣れたものを使用する方が快適かもしれません。

もう 1 つのオプションは、 ParallelEnumerable.Selectを使用することです。これは、より厳密に行おうとしていることと一致します。繰り返しますが、目にするパフォーマンスの違いは無視できる可能性が高く、知っていることに固執することには何の問題もありません。

いつものように、これのパフォーマンスが重要な場合は、試して測定する以外に方法はありません。

于 2013-03-20T15:58:00.107 に答える