3

ソリューション内の特定のループの周りにパターンを構築して、要因に応じてそれらをシリアルまたはパラレルで実行できるようにします。以下はその一般的な形式です。

並行コレクションは通常のコレクションと共通のインターフェースを共有しないため、一般的なコードを作成するには、ある種のアダプターが必要です。

特にループ本体でのデリゲートの使用に関してaddFunc、長期的に見落とす可能性のある問題を引き起こす可能性のあるものはありますか?今のところ問題なく動作しますが....?

Action<SomeType> addFunc;

if(runInParallel)
{
   addFunc = concurrentBag.Add;
   loopDelegate = Parallel.ForEach;
}
else
{
   addFunc = iList.Add;
   loopDelegate = Serial.ForEach; // wrapper delegate for foreach
}

loopDelegate(source, item =>
{
   SomeType result = longRunningTask(item);
   ...
   addFunc(result); // will this 
});
4

1 に答える 1

2

.NET 4.0でTPLを使用してみませんか? http://msdn.microsoft.com/en-us/library/dd537609.aspx

TPLを開発する際に考慮した優れたホワイトペーパーがあります。.NET4を使用できない場合は、ペーパーを見て、そこにあるいくつかの落とし穴を検討する必要があります。

明らかなことを指摘するコメントに基づいて更新されました。

私は次のような構文糖衣を使用します

ForEach<Tsource>(Predicate<IEnumerable<TSource>> isParallel, IEnumerable<TSource> source, Action<TSource> body)
{
    if(isParallel(source))
    {
        Parallel.ForEach<TSource>(source, body);
    }
    else
    {
        foreach (TSource element in source)
        {
            body(element);
        }
    }
}

実装には2つの主な利点があります。

  1. 2回列挙します。1回はループするアイテムを追加するため、2回目は実行中に列挙します。
  2. すぐにはわかりませんが、Parallel.ForEachを停止し、foreachが最も効率的なゲッターを使用しないようにします。Parallel.ForeEachは、IEnumerableで常にGetEnumeratorを使用するとは限りません。アイテムがIListを実装している場合、設計上、列挙子は同時ではありません。Parallel.ForEachはインデクサーを使用して、列挙子がリストを反復処理するのを待たずに、各スレッドがソース内の要素にアクセスできるようにします。ConcurrentBagはIListを実装していません。

これは私が参照していた論文、http://www.microsoft.com/download/en/details.aspx? displaylang = en&id=19222です。

あなたがこれを実行しているなら、それはすべて非常に良い読み物ですが、ページ1 [5-7]、26、3[0-2]に特に注意を払ってください。

シンタックスシュガーは、TPLの場合と同じように呼び出すことができることを意味します。

MyParllelLibrary.ForEach( (list) => true, list), item =>
{
    // What my code does
});
于 2012-04-16T12:55:50.010 に答える