web-dev-qa-db-ja.com

C#で実行時間を測定する

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

オプション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");

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

プロダクションコードにはどちらのオプションが適していますか、それとも他の誰かが別の何かを使用しているのでしょうか。

37
Jake

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

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

具体的には、FrequencyフィールドとGetTimestampメソッドを、管理されていないWin32 APIのQueryPerformanceFrequencyQueryPerformanceCounterの代わりに使用できます。

これらのWin32 API [ここ]とリンクされたMSDNドキュメント 2 に詳細な背景があります。

高解像度タイマー

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

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

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

28
Steve Townsend

StopWatchの方が正確であるだけでなく、DateTime.Nowが一部の状況で誤った結果をもたらすこともあります。

たとえば、夏時間の切り替え中に何が起こるかを考えてみましょう。DateTime.Nowを使用すると、実際にはnegativeの回答が得られます。

13
porges

通常、このような状況ではStopWatchを使用します。

[〜#〜] msdn [〜#〜] ページから:

StopWatch

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

次の投稿では、LINQとPLINQの実行時間を比較するために使用します。

Parallel LINQ(PLINQ)with Visual Studio 201

6

それほど重要ではないとあなたが言っているので、どちらもパフォーマンスに悪影響を与えません。 StopWatchの方が適切と思われます。時刻から時刻を減算するだけで、日付から日付を減算することはありません。日付のものは、処理するのに少し多くのメモリとCPU時間を必要とします。複数の場所で再利用する場合に備えて、コードをよりクリーンにする方法もあります。 usingのオーバーロードが頭に浮かびます。例を探します。 OK、盗まれたコード:

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);
    }
}
5
Hamish Grubijan

どちらもおそらくあなたのニーズにうまく適合しますが、StopWatchを使用すると思います。どうして?なぜなら、それはあなたがしているタスクのためのものです。

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

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

1
fyjham

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

例えば。

var tester = new PerformanceTester(() => SomeMethod());
tester.MeasureExecTime(1000);
Console.Writeline(string.Format("Executed in {0} milliseconds", tester.AverageTime.TotalMilliseconds));
1
Luke Lowrey

以下のコードを使用

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();
0
parvez

私はハミッシュの答えを単純化し、どこかにログインする必要がある場合に備えて少し一般的にしました:

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);
    }

}
0
katbyte