37

コードの実行を測定したいのですが、これを行うための最良の方法は何ですか?

オプション1:

DateTime StartTime = DateTime.Now;

//Code

TimeSpan ts = DateTime.Now.Subtract(StartTime);
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
        ts.Hours, ts.Minutes, ts.Seconds,
        ts.Milliseconds / 10);
Console.WriteLine(elapsedTime, "RunTime");

オプション 2: System.Diagnostics を使用する。

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

    //Code

    stopWatch.Stop();
    // Get the elapsed time as a TimeSpan value.
    TimeSpan ts = stopWatch.Elapsed;

    // Format and display the TimeSpan value.
    string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
        ts.Hours, ts.Minutes, ts.Seconds,
        ts.Milliseconds / 10);
    Console.WriteLine(elapsedTime, "RunTime");

これは単なるベンチマーク用ではなく、実際にはアプリケーションの一部です。関数の実行にかかる時間は関連データです。ただし、アトミックまたは超正確である必要はありません。

プロダクションコードにはどちらのオプションが適していますか、または他の誰かが別の、おそらくより優れたものを使用していますか?

4

8 に答える 8

28

このStopwatchクラスは、特に経過時間を測定するように設計されており、(ハードウェアで利用可能な場合) 基礎となる高周波ハードウェア タイマーを使用して、優れた粒度/精度を提供する場合があります。したがって、これが最良の選択のようです。

IsHighResolutionプロパティを使用して、高解像度のタイミングが利用可能かどうかを判断できます。ドキュメントによると、このクラスは、正確なタイミングのために「利用可能な最良の」Win32 API のラッパーを提供します。

特に、このFrequencyフィールドと GetTimestampメソッドは、アンマネージ Win32 API QueryPerformanceFrequencyと の代わりに使用できますQueryPerformanceCounter

これらの Win32 API の詳細な背景については、[こちら] およびリンクされた MSDN ドキュメント2を参照してください。

高解像度タイマー

カウンタは、増加する変数を参照するためにプログラミングで使用される一般的な用語です。一部のシステムには、高解像度の経過時間を提供する高解像度のパフォーマンス カウンターが含まれています。

システムに高解像度のパフォーマンス カウンターが存在する場合は、QueryPerformanceFrequency 関数を使用して、1 秒あたりのカウント数で頻度を表すことができます。カウントの値はプロセッサに依存します。たとえば、一部のプロセッサでは、カウントはプロセッサ クロックのサイクル レートである場合があります。

QueryPerformanceCounter関数は、高解像度パフォーマンス カウンターの現在の値を取得します。コードのセクションの最初と最後でこの関数を呼び出すことにより、アプリケーションは基本的にカウンターを高精度タイマーとして使用します。たとえば、 QueryPerformanceFrequencyが、高解像度パフォーマンス カウンターの頻度が 1 秒あたり 50,000 カウントであることを示しているとします。アプリケーションが 時間を計るコード セクションの直前と直後にQueryPerformanceCounterを呼び出す場合、カウンター値はそれぞれ 1500 カウントと 3500 カウントになる可能性があります。これらの値は、コードの実行中に 0.04 秒 (2000 カウント) が経過したことを示します。

于 2010-10-11T02:49:51.310 に答える
13

StopWatchより正確であるだけでなくDateTime.Now、状況によっては誤った結果が得られることもあります。

たとえば、夏時間の切り替え中に何が起こるかを考えてみDateTime.Nowください。

于 2010-10-11T02:58:42.617 に答える
6

私は一般的StopWatchにこのような状況で使用します。

MSDNページから:

ストップウォッチ

経過時間を正確に測定するために使用できる一連のメソッドとプロパティを提供します。

次の投稿では、これを使用して LINQ と PLINQ の実行時間を比較します。

Visual Studio 2010 での Parallel LINQ (PLINQ)

于 2010-10-11T02:47:43.947 に答える
5

それほど重要ではないと言うので、どちらもパフォーマンスを損なうことはありません。StopWatch の方が適切なようです。時間から時間を差し引いているだけで、ある日付から別の日付を差し引いているわけではありません。日付の処理には、メモリと CPU 時間が少しかかります。複数の場所でコードを再利用する予定がある場合は、コードをよりクリーンにする方法もあります。オーバーロードusingが思い浮かびます。例を探してみます。わかりました、コードは次から盗まれました:

http://stevesmithblog.com/blog/great-uses-of-using-statement-in-c/

public class ConsoleAutoStopWatch : IDisposable
{
    private readonly Stopwatch _stopWatch;

    public ConsoleAutoStopWatch()
    {
        _stopWatch = new Stopwatch();
        _stopWatch.Start();
    }

    public void Dispose()
    {
        _stopWatch.Stop();
        TimeSpan ts = _stopWatch.Elapsed;

        string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
                                           ts.Hours, ts.Minutes, ts.Seconds,
                                           ts.Milliseconds / 10);
        Console.WriteLine(elapsedTime, "RunTime");
    }
}

private static void UsingStopWatchUsage()
{
    Console.WriteLine("ConsoleAutoStopWatch Used: ");
    using (new ConsoleAutoStopWatch())
    {
        Thread.Sleep(3000);
    }
}
于 2010-10-11T02:46:37.353 に答える
1

どちらもあなたのニーズにうまく適合する可能性がありますが、私は use StopWatch. なんで?それはあなたがしている仕事のためのものだからです。

現在の日付/時刻を返すように構築された 1 つのクラスがあり、これはたまたまタイミングを計るために使用できます。また、タイミングを計るために特別に設計されたクラスが 1 つあります。

この場合、ミリ秒の精度が必要な場合にのみ違いが実際に存在します (その場合StopWatchはより正確です) が、一般的な原則として、探しているタスク専用のツールが存在する場合は、それを使用する方が適切です。

于 2010-10-11T02:58:37.683 に答える
1

私はこの種のことをアドホックに行うための小さなクラスを持っています。ストップウォッチ クラス - c# マイクロ パフォーマンス テストを使用します。

例えば。

var tester = new PerformanceTester(() => SomeMethod());
tester.MeasureExecTime(1000);
Console.Writeline(string.Format("Executed in {0} milliseconds", tester.AverageTime.TotalMilliseconds));
于 2010-10-11T06:12:33.753 に答える
0

以下のコードを使用

DateTime dExecutionTime;
dExecutionTime = DateTime.Now;
      TimeSpan span = DateTime.Now.Subtract(dExecutionTime);
                  lblExecutinTime.Text = "total time taken " +   Math.Round(span.TotalMinutes,2) + " minutes .   >>---> " + DateTime.Now.ToShortTimeString();
于 2012-03-16T16:33:29.380 に答える
0

ハミッシュの答えを単純化し、別の場所にログインする必要がある場合に備えて、もう少し一般的なものにしました。

public class AutoStopWatch : Stopwatch, IDisposable {

    public AutoStopWatch() {
        Start();
    }

    public virtual void Dispose() {
        Stop();
    }
}

 public class AutoStopWatchConsole : AutoStopWatch {

    private readonly string prefix;

    public AutoStopWatchConsole(string prefix = "") {
        this.prefix = prefix;
    }

    public override void Dispose() {
        base.Dispose();

        string format = Elapsed.Days > 0 ? "{0} days " : "";
        format += "{1:00}:{2:00}:{3:00}.{4:00}";

        Console.WriteLine(prefix + " " + format.Format(Elapsed.Days, Elapsed.Hours, Elapsed.Minutes, Elapsed.Seconds, Elapsed.Milliseconds / 10));
    }
}

private static void Usage() {

    Console.WriteLine("AutoStopWatch Used: ");
    using (var sw = new AutoStopWatch()) {
        Thread.Sleep(3000);

        Console.WriteLine(sw.Elapsed.ToString("h'h 'm'm 's's'"));
    }

    Console.WriteLine("AutoStopWatchConsole Used: ");
    using (var sw = new AutoStopWatchConsole()) {
        Thread.Sleep(3000);
    }

}
于 2013-10-12T00:05:32.163 に答える