13

リスト内の要素に対して徹底的なペアワイズ比較を行うメソッドを並列化する必要があります。シリアル実装は簡単です:

foreach (var element1 in list)
    foreach (var element2 in list)
        foo(element1, element2);

この場合、foo は element1 または element2 の状態を変更しません。ネストされた Parallel.ForEach ステートメントを単純に実行するのは安全ではないことはわかっています。

Parallel.ForEach(list, delegate(A element1)
{
    Parallel.ForEach(list, delegate(A element2)
    {
        foo(element1, element2);
    });
});

並列タスク ライブラリを使用してこれを実装する理想的な方法は何でしょうか?

4

3 に答える 3

16

少なくとも、コアの数がリスト内のアイテムの数の少なくとも2倍であるマシンでコードを実行している場合は、埋め込みを実行することをお勧めしますParallel.ForEach

つまり、クアッドコアをターゲットにしていて、リストに1,000個のアイテムがある場合は、親ループを並列化するだけです。両方のループを並列化しても、コードは速くなりませんが、並列タスクにはパフォーマンスコストがかかるため、かなり遅くなります。

代替テキストhttp://www.freeimagehosting.net/uploads/ca97f403f8.png

Parallel.ForEach各反復で、次の反復を実行する必要があるスレッドを決定するために、数ミリ秒が失われます。7つのアイテムのセットがあるとします。親ループを並列化すると、それらのミリ秒は7回失われます。両方のループを並列化すると、代わりに7×7=49回失われます。セットが大きいほど、過熱が大きくなります。

于 2010-07-19T13:52:51.003 に答える
12

パラレルループとノーマルループを1つずつだけ持つことはできませんか?だからどちらか

Parallel.ForEach(list、delegate(A element1)
{{
  foreach(リスト内のelement2)
    foo(element1、element2)
});

また

foreach(リスト内のelement1)
{{
  Parallel.ForEach(list、delegate(A element2)
  {{
    foo(element1、element2);
  });
}

同様にそれをスピードアップする必要があります。とにかくサイクルごとにスレッドが存在することは決してなかったので、これはおそらくネストされた並列ループと同じくらい速いか、わずかに遅いでしょう。

于 2010-07-19T13:52:22.933 に答える
1

ネストされた 2 つのループは、基本的に、リストとそれ自体のデカルト積をfooする必要があることを意味します。最初にすべてのペアを一時リストに作成し、次にそのリストを Parallel.ForEach で反復処理することにより、操作全体を並列化できます。

EDIT : すべての組み合わせのリストを作成する代わりに、イテレーターを使用して組み合わせで 2 要素のタプルを返すことができます。Parallel.ForEach は引き続きタプルの処理を並列化します。

次のサンプルは、現在の反復ステップを出力して、並列処理中に予想されるように、結果が順不同で返されることを示しています。

 const int SIZE = 10;
    static void Main(string[] args)
    {
        List<int> list = new List<int>(SIZE);
        for(int i=0;i<SIZE;i++)
        {
            list.Add(i);
        }


        Parallel.ForEach(GetCombinations(list),(t,state,l)=>
            Console.WriteLine("{0},{1},{2}",l,t.Item1,t.Item2));

    }

    static IEnumerable<Tuple<int,int>> GetCombinations(List<int> list)
    {
        for(int i=0;i<list.Count;i++)
            for(int j=0;j<list.Count;j++)
                yield return Tuple.Create(list[i],list[j]);
    }
于 2010-07-19T14:07:41.620 に答える