4

次のように、通常の for each ループ内で Parallel.foreach と Task を使用することの違いを特定するのに役立つドキュメント/記事がありますか?

ケース 1 - Parallel.foreach:

Parallel.foreach
{
  // Do SOmething thread safe: parsing an xml and then save 
  // into a DB Server thry respoitory approach
}

ケース 2 - foreach 内のタスク:

foreach
{
  Task t1 = Task.factory.startNew(()=>
  {
     //Do the same thing as case 1 that is thread safe
  }
}
Task.waitall()
  • 私は独自のテストを行い、その結果、ケース 1 のパフォーマンスがケース 2 よりも優れていることが示されました。比率は次のようになります: シーケンシャル vs ケース 1 vs ケース 2 = 5 秒 : 1 秒 : 4 秒

ケース 1 とケース 2 はほぼ 1:4 ですが、? では、ループ内で並列に実行したい場合は、常に parallel.foreach または parallel.for を使用する必要があるということですか?

4

3 に答える 3

1

まず、このテーマに関する最良のドキュメントは、C# による CLR のパート V です。

http://www.amazon.com/CLR-via-C-Developer-Reference/dp/0735667454/ref=sr_1_1?ie=UTF8&qid=1376239791&sr=8-1&keywords=clr+via+c%23

次に、Parallel.Foreach はタスクを作成するだけでなくグループ化するため、パフォーマンスが向上することを期待しています。Jeffrey Richter の著書では、個別に開始されたタスクはスレッド プール キューに置かれると説明しています。実際のスレッド プール キューをロックするには、いくらかのオーバーヘッドがあります。これに対抗するために、タスク自体には、作成したタスク用の独自のキューがあります。タスクによって保持されるこのタスク サブキューは、ロックせずに実際にいくつかの作業を実行できます。

その章 (第 27 章) をもう一度読む必要があるため、Parallel.Foreach がこのように機能するかどうかはわかりませんが、これは私が期待することです。

彼は、ロックはカーネル レベルの構成要素にアクセスする必要があるため、コストがかかると説明しています。

いずれの場合も、それらが順次処理されることを期待しないでください。Parallel.Foreach を使用すると、前述の内部構造により、 foreach キーワードよりも順次処理される可能性が低くなります。

于 2013-08-11T16:56:00.860 に答える
1

ループの反復を処理するためにParallel.ForEach()少数の s を作成するということです。は比較的安価ですが、無料ではないため、パフォーマンスが向上する傾向があります。ループの本体はすばやく実行され、改善は非常に大きくなる可能性があります。これは、観察している動作の最も可能性の高い説明です。TaskTask

于 2013-08-11T12:25:59.817 に答える
0

いくつのタスクを実行していますか? 十分にループしている場合、新しいタスクを作成するだけでもかなりの時間がかかる可能性があります。つまり、以下は最初のブロックが 15 ミリ秒で実行され、2 番目のブロックが 1 秒以上かかり、2 番目のブロックはタスクを実行しません。のコメントを外すStartと、時間が 3 秒近くになります。WaitAll少量を追加するだけです。

static class Program
{
    static void Main()
    {
        const int max = 3000000;
        var range = Enumerable.Range(0, max).ToArray();
        {
            var sw = new Stopwatch();
            sw.Start();
            Parallel.ForEach(range, i => { });
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);
        }
        {
            var tasks = new Task[max];
            var sw = new Stopwatch();
            sw.Start();
            foreach (var i in range)
            {
                tasks[i] = new Task(()=> { });
                //tasks[i].Start();
            }
            //Task.WaitAll(tasks);
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);
        }
    }
}
于 2013-08-10T17:14:01.117 に答える