DateTime.Nowは関数のパフォーマンスを測定する最良の方法ですか?


474

ボトルネックを見つけ、時間をできるだけ正確に測定する必要があります。

次のコードスニペットは、パフォーマンスを測定するための最良の方法ですか?

DateTime startTime = DateTime.Now;

// Some execution process

DateTime endTime = DateTime.Now;
TimeSpan totalTimeTaken = endTime.Subtract(startTime);

ちなみに、何かを探していない場合は、高速でダーティなパフォーマンスカウンターを使用できます。
ジョナサンCディキンソン

1
より高い精度が必要な場合は、Stopwatch.GetTimestampを使用します。それ以外の場合は適切です。
dbasnett

@dbasnett回答を詳しく説明できますか?
David Basarab、2011年

上記の例では、startとendtimeをlongに変更し、DateTime.NowではなくStopwatch.GetTimestampを割り当てます。所要時間は(end-start)/Stopwatch.Frequencyです。
dbasnett 2011年

回答:


649

いいえ、ちがいます。ストップウォッチを使用する(内System.Diagnostics

Stopwatch sw = Stopwatch.StartNew();
PerformWork();
sw.Stop();

Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds);

ストップウォッチは、高精度タイマーの存在を自動的にチェックします。

言及する価値があるのDateTime.NowDateTime.UtcNow、タイムゾーンやDSTなどで行わなければならない作業が原因である場合よりも、かなり遅い場合があることです。

DateTime.UtcNowの解像度は通常15ミリ秒です。優れた要約については、精度に関するJohn Chapmanのブログ投稿を参照してくださいDateTime.Now

興味深い雑学:DateTime.UtcNowハードウェアが高周波カウンターをサポートしていない場合、ストップウォッチはフォールバックします。静的フィールドStopwatch.IsHighResolutionを調べることにより、ストップウォッチがハードウェアを使用して高精度を達成しているかどうかを確認できます。


3
私は1つのPerformWork();を配置します。「ヒートアップ」のためのストップウォッチの前。
DiVan、2011年

2
また、PerformWork()非常に短い場合は繰り返し呼び出して、呼び出しのバッチの平均を計算できる場合があるという推奨も追加する必要があります。また、Stopwatchタイミング測定を濁らせるストロボ効果を回避するために、開始/停止するのではなく、呼び出し全体の時間を計ってください。
devgeezer 2012

1
マルチコアではストップウォッチはスレッドセーフではありません。stackoverflow.com/questions/6664538/…およびstackoverflow.com/questions/1149485/…を
Pavel Savara

1
sw.ElapsedMilliseconds; することもできます
Flappy

2
@Pavel、明確にするために、ストップウォッチは、Windows 7およびWindows 8で実行されている最新のマルチコアプロセッサ上で最高のソリューション(低オーバーヘッドと高い精度)としてMicrosoftが推奨されmsdn.microsoft.com/en-us/library/windows/をデスクトップ/…
Ron

91

あなたが速くて汚い何かが欲しいなら、私はより高い精度のために代わりにストップウォッチを使うことを勧めます。

Stopwatch sw = new Stopwatch();
sw.Start();
// Do Work
sw.Stop();

Console.WriteLine("Elapsed time: {0}", sw.Elapsed.TotalMilliseconds);

あるいは、もう少し高度なものが必要な場合は、おそらくANTSなどのサードパーティのプロファイラーの使用を検討する必要があります。


56

この記事では、まず、すべてのあなたは3つの選択肢を比較する必要があると述べているStopwatchDateTime.NowDateTime.UtcNow

また、場合によっては(パフォーマンスカウンターが存在しない場合)、ストップウォッチがDateTime.UtcNow +いくつかの追加処理を使用していることも示しています。そのため、その場合はDateTime.UtcNowが最良のオプションであることは明らかです(他のユーザーがそれを使用するため+一部の処理)

しかし、結局のところ、カウンターはほとんど常に存在します-.NETストップウォッチに関連する高解像度パフォーマンスカウンターとその存在についての説明を参照してください

こちらがパフォーマンスグラフです。パフォーマンスコストがUtcNowが他の方法と比べてどれほど低いかに注意してください。

ここに画像の説明を入力してください

X軸はサンプルデータサイズであり、Y軸は例の相対時間です。

1つStopwatch優れている点は、より高い分解能の時間測定を提供することです。もう1つは、オブジェクト指向の性質です。ただし、OOラッパーを作成するのはUtcNow難しくありません。


最初のリンクは壊れているようです。
Peter Mortensen

1
タイムマシンがそれを示すことができると思います。ところで、「三人」を編集する理由は、ここでは不要だと思います。
Valentin Kuzub 2013年

18

ベンチマークコードをユーティリティクラス/メソッドにプッシュすると便利です。StopWatchクラスは、である必要はありませんDisposedか、Stoppedエラーに。したがって、いくつかのアクションのタイミングを決める最も簡単なコードは

public partial class With
{
    public static long Benchmark(Action action)
    {
        var stopwatch = Stopwatch.StartNew();
        action();
        stopwatch.Stop();
        return stopwatch.ElapsedMilliseconds;
    }
}

呼び出しコードの例

public void Execute(Action action)
{
    var time = With.Benchmark(action);
    log.DebugFormat(“Did action in {0} ms.”, time);
}

拡張メソッドのバージョンはこちら

public static class Extensions
{
    public static long Benchmark(this Action action)
    {
        return With.Benchmark(action);
    }
}

そして、サンプルの呼び出しコード

public void Execute(Action action)
{
    var time = action.Benchmark()
    log.DebugFormat(“Did action in {0} ms.”, time);
}

1
より良い粒度についてはどうですか?多くのことが1ミリ秒未満で発生します。
Henrik、

次に、Elapsedプロパティを返します。これはTimeSpanです。私はあなたにパターンを示しているだけです。実装して楽しんでください。
アンソニー・マストリアン

Elapsed.TotalMillisecondsより高い精度のために戻ります。あまりにもこの質問を参照してくださいstackoverflow.com/questions/8894425/...
nawfal


13

System.Diagnostics.Stopwatchクラスを使用します。

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

// Do some code.

sw.Stop();

// sw.ElapsedMilliseconds = the time your "do some code" took.

11

同上ストップウォッチ、それははるかに優れています。

パフォーマンス測定については、「//実行プロセス」が非常に短いプロセスかどうかも確認する必要があります。

また、「//一部の実行プロセス」の最初の実行は、後続の実行よりもかなり遅くなる可能性があることにも注意してください。

通常、メソッドをループで1000回または1000000回実行してテストし、1回実行するよりもはるかに正確なデータを取得します。


9

これらはすべて時間を測定する優れた方法ですが、それはボトルネックを見つける非常に間接的な方法にすぎません。

スレッド内のボトルネックを見つける最も直接的な方法は、スレッドを実行することです。待機している処理を実行している間は、一時停止またはブレークキーを使用して停止します。これを数回繰り返します。ボトルネックにX%の時間がかかる場合、X%は各スナップショットのアクションでそれをキャッチする確率です。

これがどのようにそしてなぜ働くかのより完全な説明はここにあります


7

@ ショーン・チェンバーズ

参考までに、.NETタイマークラスは診断用ではなく、次のように、事前に設定された間隔でイベントを生成します(MSDNから)。

System.Timers.Timer aTimer;
public static void Main()
{
    // Create a timer with a ten second interval.
    aTimer = new System.Timers.Timer(10000);

    // Hook up the Elapsed event for the timer.
    aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);

    // Set the Interval to 2 seconds (2000 milliseconds).
    aTimer.Interval = 2000;
    aTimer.Enabled = true;

    Console.WriteLine("Press the Enter key to exit the program.");
    Console.ReadLine();
}

// Specify what you want to happen when the Elapsed event is 
// raised.
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
    Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}

したがって、これは実際に何かがかかった時間を知るのに役立ちません。一定の時間が経過しただけです。

タイマーはSystem.Windows.Formsのコントロールとしても公開されています... VS05 / VS08のデザイナーツールボックスで確認できます


6

これは正しい方法です:

using System;
using System.Diagnostics;

class Program
{
    public static void Main()
    {
        Stopwatch stopWatch = Stopwatch.StartNew();

            // some other code

        stopWatch.Stop();

        // this not correct to get full timer resolution
        Console.WriteLine("{0} ms", stopWatch.ElapsedMilliseconds);

        // Correct way to get accurate high precision timing
        Console.WriteLine("{0} ms", stopWatch.Elapsed.TotalMilliseconds);
    }
}

詳細については、正確なパフォーマンスカウンターを取得するためにDataTimeの代わりにストップウォッチ使用するを参照してください


6

Visual Studio Team Systemには、この問題に役立ついくつかの機能があります。基本的に、単体テストを作成し、さまざまなシナリオでそれらを混合して、ストレステストまたは負荷テストの一部としてソフトウェアに対して実行できます。これは、アプリケーションのパフォーマンスに最も影響を与えるコードの領域を特定するのに役立ちます。

MicrosoftのPatterns and Practicesグループには、Visual Studio Team System Performance Testing Guidanceにいくつかのガイダンスがあります。


5

Vance Morrisonのブログで彼が書いたCodeTimerクラスについての投稿を見つけたところです。これにより、使用がStopWatch簡単になり、面倒なことをいくつか行うことができます。


5

これは十分に専門的ではありません:

Stopwatch sw = Stopwatch.StartNew();
PerformWork();
sw.Stop();

Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds);

より信頼性の高いバージョンは次のとおりです。

PerformWork();

int repeat = 1000;

Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < repeat; i++)
{
   PerformWork();
}

sw.Stop();

Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds / repeat);

実際のコードでは、GC.Collect呼び出しを追加してマネージヒープを既知の状態に変更し、ETWプロファイルでコードの異なる間隔を簡単に分離できるようにSleep呼び出しを追加します。


4

私はこの種のパフォーマンスチェックをほとんど行わなかったので(「これは遅い、速くする」と思う傾向がある)ので、私はほとんどいつもこれを行ってきました。

グーグルはパフォーマンスチェックのための多くのリソース/記事を明らかにしています。

pinvokeを使用してパフォーマンス情報を取得することについて多くの人が言及しています。私が研究している資料の多くは、実際にはperfmonの使用についてのみ言及しています。

編集:

StopWatchの話を見てください。私は何かを学びました:)

これは良い記事のようです


4

プログラム内で使用する方法は、次に示すようにStopWatchクラスを使用することです。

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


// Critical lines of code

long elapsedMs = sw.Elapsed.TotalMilliseconds;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.