6

私は非常に最小限の例を試しました:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Collections.Concurrent;
using System.Diagnostics;

namespace TPLExample {
    class Program {
        static void Main(string[] args) {
            int[] dataItems = new int[100];
            double[] resultItems = new double[100];

            for (int i = 0; i < dataItems.Length; ++i) {
                dataItems[i] = i;
            }

            Stopwatch stopwatch = new Stopwatch();

            stopwatch.Reset();
            stopwatch.Start();
            Parallel.For(0, dataItems.Length, (index) => {
                resultItems[index] = Math.Pow(dataItems[index], 2);
            });
            stopwatch.Stop();
            Console.WriteLine("TPL Time elapsed: {0}", stopwatch.Elapsed);

            stopwatch.Reset();
            stopwatch.Start();
            for (int i = 0; i < dataItems.Length; ++i) {
                resultItems[i] = Math.Pow(dataItems[i], 2);
            }
            stopwatch.Stop();
            Console.WriteLine("Sequential Time elapsed: {0}", stopwatch.Elapsed);

            WaitForEnterKey();
        }

        public static void WaitForEnterKey() {
            Console.WriteLine("Press enter to finish");
            Console.ReadLine();
        }

        public static void PrintMessage() {
            Console.WriteLine("Message printed");
        }
    }
}

出力は次のとおりです。

TPL Time elapsed: 00:00:00.0010670
Sequential Time elapsed: 00:00:00.0000178
Press enter to finish

シーケンシャルループはTPLよりもはるかに高速です!これはどのように可能ですか?私の理解では、内の計算Parallel.Forは並行して実行されるので、より速くする必要がありますか?

4

4 に答える 4

10

簡単に言えば、100を超えるアイテムを繰り返し、小さな数学演算を実行するだけの場合、新しいスレッドを生成してそれらが完了するのを待つと、ループを実行するよりも多くのオーバーヘッドが発生します。

私の理解では、Parallel.For内の計算は並列で実行されるので、より高速である必要がありますか?

人々がコンピューターのパフォーマンスについて大胆な発言をするときに一般的に起こるように、ここでははるかに多くの変数が働いており、実際にその仮定をすることはできません。たとえば、ループ内では、プロセッサが非常に高速に実行できる、for以上のことは何もしていません。Math.PowこれがI/Oを多用する操作であり、各スレッドが長時間待機する必要がある場合、または一連のプロセッサを多用する操作であったとしても、並列処理をさらに活用できます(マルチスレッドプロセッサがある場合)。 。しかし、現状では、これらのスレッドを作成して同期するオーバーヘッドは、並列処理によって得られる利点よりもはるかに大きくなります。

于 2012-05-26T02:39:41.013 に答える
10

並列ループ処理は、ループ内で実行される操作に比較的コストがかかる場合に役立ちます。例で行っているのは、指数を計算することだけです。これは簡単です。マルチスレッドのオーバーヘッドは、この場合に得られる利益をはるかに上回っています。

于 2012-05-26T02:41:27.013 に答える
2

このコード例は、上記の非常に優れた答えの実用的な証拠です。

Thead.Sleepでスレッドをブロックするだけで、集中的なプロセッサ操作をシミュレートしました。

出力は次のとおりです。

  • シーケンシャルループ-00:00:09.9995500
  • 並列ループ-00:00:03.0347901

_

class Program
{
    static void Main(string[] args)
    {
        const int a = 10;

        Stopwatch sw = new Stopwatch();
        sw.Start();

        //for (long i = 0; i < a; i++)
        //{
        //    Thread.Sleep(1000);
        //}

        Parallel.For(0, a, i =>
        {
            Thread.Sleep(1000);
        });

        sw.Stop();

        Console.WriteLine(sw.Elapsed);

        Console.ReadLine();
    }
}
于 2012-08-17T12:37:13.760 に答える
1

並列化のオーバーヘッドは、Math.Powを100回連続して実行するよりもはるかに大きくなります。他の人はこれを言っています。

さらに重要なことに、シーケンシャルバージョンではメモリアクセスは簡単ですが、パラレルバージョンでは、スレッドはメモリ(resultItems)を共有する必要があり、そのようなことは、100万個のアイテムがある場合でも本当にあなたを殺します。

並列プログラミングに関する この優れたMicrosoftホワイトペーパーの44ページを参照してください:http: //www.microsoft.com/en-us/download/details.aspx? id=19222 。これは、このテーマに関するMSDNマガジンの記事です:http://msdn.microsoft.com/en-us/magazine/cc872851.aspx

于 2012-05-26T03:03:24.887 に答える