ここでは、ベンチマークを計るときなどのように、ある時点からある時点までの時間をより高い精度で計測する方法を紹介します。
.NET Framework 2.0以降では、Stopwatchクラスを使うことにより、経過時間を高い精度で計測することができます。
使い方は非常に簡単で、Startメソッドで計測を開始し、Stopメソッドで停止し、Elapsedプロパティで経過時間を取得します。
'Stopwatchオブジェクトを作成する Dim sw As New System.Diagnostics.Stopwatch() 'ストップウォッチを開始する sw.Start() '次のようにStartNewメソッドを使うと、上の2行と同じことが1行でできる 'Dim sw As System.Diagnostics.Stopwatch = System.Diagnostics.Stopwatch.StartNew() '時間を計測したい処理がここにあるものとする For i As Integer = 0 To 9 System.Threading.Thread.Sleep(100) Next 'ストップウォッチを止める sw.Stop() '結果を表示する Console.WriteLine(sw.Elapsed)
//Stopwatchオブジェクトを作成する System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); //ストップウォッチを開始する sw.Start(); //次のようにStartNewメソッドを使うと、上の2行と同じことが1行でできる //System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew(); //時間を計測したい処理がここにあるものとする for (int i = 0; i < 10; i++) { System.Threading.Thread.Sleep(100); } //ストップウォッチを止める sw.Stop(); //結果を表示する Console.WriteLine(sw.Elapsed);
Stopwatchクラスは、高解像力(高分解能)パフォーマンスカウンタがサポートされていればそれを使い、サポートされていなければシステムタイマを使用します。Stopwatchクラスが高解像力パフォーマンスカウンタを使用している時は、Stopwatch.IsHighResolutionフィールドがTrueになります。
また、タイマの精度を示すタイマ頻度は、Stopwatch.Frequencyフィールドで分かります。Frequencyフィールドの値は、1秒あたりのタイマ刻みの数(カウンタのカウント数)です。
Stopwatchクラスには、経過時間を返す3つのプロパティがあります。Elapsedプロパティは、経過時間をTimeSpan型で返します。ElapsedMillisecondsプロパティは、ミリ秒単位の整数を返します。
ElapsedTicksプロパティは、タイマ刻みの数を返します。この値を秒単位に変換するには、Frequencyフィールドで割る必要があります。しかしElapsedとElapsedMillisecondsプロパティの値はElapsedTicksをFrequencyで割ったものですので、自分で計算する必要はないでしょう。
1つのStopwatchオブジェクトでStartとStopを繰り返すと、経過時間は累計されていきます。経過時間を0にリセットするには、Resetメソッドを呼び出します。
以下の例で、StopしてからStartで再開するまでにResetでリセットしないと経過時間が累計されることを確認してください。
'ストップウォッチを開始する Dim sw As System.Diagnostics.Stopwatch = System.Diagnostics.Stopwatch.StartNew() '1秒待機 System.Threading.Thread.Sleep(1000) 'ストップウォッチを止める sw.Stop() '結果を表示する Console.WriteLine(sw.Elapsed) '結果例: 00:00:00.9990679 'ストップウォッチを再開する sw.Start() '1秒待機 System.Threading.Thread.Sleep(1000) '結果を表示する Console.WriteLine(sw.Elapsed) '結果例: 00:00:01.9989872 'ストップウォッチをリセットしてから再開する sw.Reset() sw.Start() '1秒待機 System.Threading.Thread.Sleep(1000) '結果を表示する Console.WriteLine(sw.Elapsed) '結果例: 00:00:00.9999094
//ストップウォッチを開始する System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew(); //1秒待機 System.Threading.Thread.Sleep(1000); //ストップウォッチを止める sw.Stop(); //結果を表示する Console.WriteLine(sw.Elapsed); //結果例: 00:00:00.9990679 //ストップウォッチを再開する sw.Start(); //1秒待機 System.Threading.Thread.Sleep(1000); //結果を表示する Console.WriteLine(sw.Elapsed); //結果例: 00:00:01.9989872 //ストップウォッチをリセットしてから再開する sw.Reset(); sw.Start(); //1秒待機 System.Threading.Thread.Sleep(1000); //結果を表示する Console.WriteLine(sw.Elapsed); //結果例: 00:00:00.9999094
Stopwatchクラスが使えない場合は、Win32 APIのQueryPerformanceCounterを使います。QueryPerformanceCounterの使い方は、「[HOW TO] Visual C# .NET で、QueryPerformanceCounter を使用してコードの時間を計測する方法」や「pinvoke.net: QueryPerformanceCounter (kernel32)」で説明されています。
以下に簡単な例を示します。
<System.Runtime.InteropServices.DllImport("kernel32.dll")> _ Private Shared Function QueryPerformanceCounter( _ ByRef lpPerformanceCount As Long) As Boolean End Function <System.Runtime.InteropServices.DllImport("kernel32.dll")> _ Private Shared Function QueryPerformanceFrequency( _ ByRef lpFrequency As Long) As Boolean End Function Private Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) _ Handles Button1.Click '開始時のカウンタを取得する Dim startCount As Long If Not QueryPerformanceCounter(startCount) Then Console.WriteLine("高解像力パフォーマンスカウンタが未サポート") Exit Sub End If '時間を計る処理がここにあるものとする System.Threading.Thread.Sleep(3000) '終了時のカウンタを取得する Dim endCount As Long QueryPerformanceCounter(endCount) '1秒あたりのカウント数を取得する Dim frequency As Long QueryPerformanceFrequency(frequency) '経過時間を秒に変換して表示する Console.WriteLine("{0}秒", CDbl((endCount - startCount)) / frequency) End Sub
[System.Runtime.InteropServices.DllImport("kernel32.dll")] static extern bool QueryPerformanceCounter(out long lpPerformanceCount); [System.Runtime.InteropServices.DllImport("kernel32.dll")] static extern bool QueryPerformanceFrequency(out long lpFrequency); //Button1のClickイベントハンドラ private void button1_Click(object sender, System.EventArgs e) { //開始時のカウンタを取得する long startCount; if (!QueryPerformanceCounter(out startCount)) { Console.WriteLine("高解像力パフォーマンスカウンタが未サポート"); return; } //時間を計る処理がここにあるものとする System.Threading.Thread.Sleep(3000); //終了時のカウンタを取得する long endCount; QueryPerformanceCounter(out endCount); //1秒あたりのカウント数を取得する long frequency; QueryPerformanceFrequency(out frequency); //経過時間を秒に変換して表示する Console.WriteLine("{0}秒", (double)(endCount - startCount) / frequency); }
QueryPerformanceCounterが使えない(高解像力パフォーマンスカウンタがサポートされていない)のであれば、システムタイマの値を使用します。具体的には、DateTime.Now.Ticksなどの値を使用します。