3

Stopwatchメソッドとfor/foreachループのプロファイルを作成するために使用するクラスを作成しました。forand loopsを使用して、または実装foreachに対して標準ループをテストします。Parallel.ForParallel.ForEach

次のようにパフォーマンステストを作成します。

方法:

PerformanceResult result = Profiler.Execute(() => { FooBar(); });

Forループ:

SerialParallelPerformanceResult result = Profiler.For(0, 100, x => { FooBar(x); });

ForEachループ:

SerialParallelPerformanceResult result = Profiler.ForEach(list, item => { FooBar(item); });

テスト(、、またはのいずれか)を実行するときはいつでも.Execute.Forパフォーマンス.ForEachが時間の経過とともにどのように変化するかを確認できるように、テストをループに入れます。

パフォーマンスの例は次のとおりです。

メソッド実行1=200ms
メソッド実行2=12ms
メソッド実行3=0ms

実行の場合1=300ms(シリアル)、100ms(パラレル)
実行の場合2 = 20ms(シリアル)、75ms(パラレル)
実行の場合3 = 2ms(シリアル)、50ms(パラレル)

ForEach実行1=350ms(シリアル)、300ms(並列)
ForEach実行2 = 24ms(シリアル)、89ms(並列)
ForEach実行3 = 1ms(シリアル)、21ms(並列)

私の質問は次のとおりです。

  1. パフォーマンスが時間の経過とともに変化するのはなぜですか。これを容易にするために、.NETはバックグラウンドで何を行っていますか?

  2. シリアル操作がパラレル操作よりも速いのはなぜですか?違いを正しく確認するために、操作を複雑にするようにしました...ほとんどの場合、シリアル操作の方が高速に見えます!?

注:並列処理の場合、8コアマシンでテストしています。

4

2 に答える 2

4

パフォーマンスプロファイリングをさらに調査した結果、ストップウォッチを使用することは特定のタスクのパフォーマンスを測定する正確な方法ではないことがわかりました。

(これについてコメントしてくれた手斧とローレンに感謝します!)

ストップウォッチが正確でない理由:

  1. 測定値は、CPU時間ではなく、ミリ秒単位の経過時間で計算されます。
  2. 測定は、バックグラウンドの「ノイズ」とスレッドを集中的に使用するプロセスの影響を受ける可能性があります。
  3. 測定では、JITのコンパイルとオーバーヘッドは考慮されません。

そうは言っても、ストップウォッチを使用することは、パフォーマンスのカジュアルな探索には問題ありません。そのことを念頭に置いて、プロファイリングアルゴリズムをいくらか改善しました。

渡された式を単純に実行する前は、式を数回反復する機能があり、平均実行時間を構築しています。ここでJITが開始され、大きなオーバーヘッドが発生する可能性があるため、最初の実行は省略できます。当然のことながら、これはRedgateのANTSプロファイラーのようなプロのプロファイリングツールを使用するほど洗練されたものにはなりませんが、より単純なタスクでも問題ありません。

于 2012-09-28T09:36:59.757 に答える
2

上記の私のコメントによると:私は自分でいくつかの簡単なテストを行いましたが、時間の経過とともに違いは見つかりませんでした。コードを共有できますか?ここに収まらないので、答えを入れます。

これは私のサンプルコードです。(静的メソッドとインスタンスメソッドの両方で違いはありませんでした)

class Program
{
    static void Main(string[] args)
    {
        int to = 50000000;
        OtherStuff os = new OtherStuff();

        Console.WriteLine(Profile(() => os.CountTo(to)));
        Console.WriteLine(Profile(() => os.CountTo(to)));
        Console.WriteLine(Profile(() => os.CountTo(to)));
    }

    static long Profile(Action method)
    {
        Stopwatch st = Stopwatch.StartNew();
        method();
        st.Stop();
        return st.ElapsedMilliseconds;
    }
}

class OtherStuff
{
    public void CountTo(int to)
    {
        for (int i = 0; i < to; i++)
        {
            // some work...
            i++;
            i--;
        }
    }
}

サンプル出力は次のようになります。

331
331
334

代わりに、このメソッドを実行することを検討してください。

class OtherStuff
    {
        public string CountTo(Guid id)
        {
            using(SHA256 sha = SHA256.Create())
            {
                int x = default(int);
                for (int index = 0; index < 16; index++)
                {
                    x = id.ToByteArray()[index] >> 32 << 16;
                }
                RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
                byte[] y = new byte[1024];
                rng.GetBytes(y);
                y = y.Concat(BitConverter.GetBytes(x)).ToArray();
                return BitConverter.ToString(sha.ComputeHash(BitConverter.GetBytes(x).Where(o => o >> 2 < 0).ToArray()));
            }
        }
    }

サンプル出力:

11 
0 
0
于 2015-01-27T19:10:11.737 に答える