こんにちは!開発現場の第一線で戦う、あなたの先輩エンジニアです。
日々の業務システム開発、お疲れ様です。「なんだかこの処理、最近重い気がするんだよなぁ……でも、どこがボトルネックなのか感覚でしか分からない」――そんなモヤモヤを抱えたことはありませんか?
「とりあえず `DateTime.Now` で時間の引き算をしておけばいいか」なんて妥協していませんか?
実は、その計測方法では正確なパフォーマンス改善の根拠(エビデンス)は掴めません。なぜなら、`DateTime.Now` はOSの時刻同期やタイムゾーン変更の影響を受けるため、ミリ秒以下の厳密な処理時間を測るにはあまりにも「おしゃべり」すぎるからです。
今回は、プロの現場で必須となる `Stopwatch` クラス を使って、CPUのハードウェアタイマーを直接叩き、ボトルネックを正確に炙り出す極上のテクニックを伝授します。ここをクリアすれば、あなたのVB.NETのコード品質は一段上のステージに到達しますよ。
—
1. なぜ `DateTime.Now` ではダメなのか?
まずは、私たちがやりがちな「NGな計測方法」を見てみましょう。
.net
‘ 【やってはいけない例】DateTime.Nowによる計測
Dim startTime As DateTime = DateTime.Now
‘ 重そうな処理(例:10万回の文字列結合)
Dim result As String = “”
For i As Integer = 1 To 100000
result &= i.ToString()
Next
Dim endTime As DateTime = DateTime.Now
Dim elapsed As TimeSpan = endTime – startTime
Console.WriteLine($”処理時間: {elapsed.TotalMilliseconds} ミリ秒”)
一見、これで動くし測れているように見えますよね。しかし、これには致命的な欠点があります。
`DateTime.Now` は「現在の壁時計(ウォールクロック時刻)」を取得しています。つまり、裏でWindowsの時刻同期サービスが走ったりすると、計測中に時間が巻き戻ったり進んだりするのです。これでは、数ミリ秒単位の正確なベンチマークなど取れません。
救世主 `System.Diagnostics.Stopwatch` とは
そこで登場するのが、`System.Diagnostics.Stopwatch` クラスです。
こいつはCPUの「高精度パフォーマンスカウンター」を利用しています。OSの時刻同期に左右されず、CPUのクロック数をベースに時間を計測するため、マイクロ秒(100万分の1秒)単位の圧倒的な精度を叩き出します。
—
2. 実践:Stopwatchを使った高精度ベンチマークの基本
それでは早速、実際のコードを見ていきましょう。
今回は、業務システムでやりがちな「非効率なループ処理」をあぶり出すシナリオを想定します。
.net
Imports System.Diagnostics
Module PerformanceAnalyzer
Sub Main()
Console.WriteLine(“=== パフォーマンス計測を開始します ===”)
‘ 1. Stopwatchのインスタンスを生成
Dim sw As New Stopwatch()
‘ 2. 計測スタート
sw.Start()
‘ — ここから計測したい処理 —
HeavyDatabaseSimulation()
‘ —————————–
‘ 3. 計測ストップ
sw.Stop()
‘ 4. 結果の出力(ElapsedMillisecondsでミリ秒を取得)
Console.WriteLine($”処理完了: {sw.ElapsedMilliseconds} ms”)
‘ より高精度に測りたい場合は ElapsedTicks や Elapsed.TotalMicroseconds も使える!
Console.WriteLine($”詳細なTicks: {sw.ElapsedTicks} ticks”)
Console.WriteLine(“=== 計測終了 ===”)
Console.ReadLine()
End Sub
‘ ざっくりとした重い処理のシミュレーション
Private Sub HeavyDatabaseSimulation()
Dim sum As Long = 0
For i As Integer = 1 To 50000000
sum += i
Next
End Sub
End Module
コードの解説とポイント
- `Dim sw As New Stopwatch()`: インスタンスを作っただけでは動きません。静かにスタンバイしている状態です。
- `sw.Start()` と `sw.Stop()`: この挟み撃ちのシンプルさが美しいですね。
- `sw.ElapsedMilliseconds`: 経過時間をミリ秒単位の整数(`Long`型)でサクッと取得できます。
—
3. 実務で使える!複数の処理を「比較・計測」するテクニック
実際の業務では、「どっちの書き方の方が速いか」を比較したい場面が多々ありますよね。例えば、「Stringの結合」と「StringBuilderの利用」の比較です。
プロフェッショナルなエンジニアは、以下のように `Restart` メソッドをスマートに使いこなします。
.net
Imports System.Text
Sub ComparePerformance()
Const LoopCount As Integer = 50000
Dim sw As New Stopwatch()
‘ — パターンA: &-演算子による文字列連結(非効率) —
sw.Start()
Dim badResult As String = “”
For i As Integer = 1 To LoopCount
badResult &= i.ToString()
For
sw.Stop()
Console.WriteLine($”[&演算子]: {sw.ElapsedMilliseconds} ms”)
‘ — パターンB: StringBuilderによる文字列構築(高効率) —
‘ ※ここで Stopwatch をリセット&再スタート!
sw.Restart()
Dim sb As New StringBuilder()
For i As Integer = 1 To LoopCount
sb.Append(i.ToString())
Next
Dim goodResult As String = sb.ToString()
sw.Stop()
Console.WriteLine($”[StringBuilder]: {sw.ElapsedMilliseconds} ms”)
End Sub
ここがプロの知見:`sw.Restart()` の重要性
一度止めたストップウォッチをもう一度最初から動かすとき、`sw.Reset()` を呼んでから `sw.Start()` を書く人がいますが、VB.NETでは `sw.Restart()` を1発叩くだけで「タイマーのクリア(リセット)」と「再スタート」を同時にやってくれます。コードがスッキリして可読性も爆上がりしますよ。
—
4. 陥りやすい罠!実務でやりがちな「3つのアンチパターン」
`Stopwatch` は強力ですが、使い方を誤ると「嘘のベンチマーク」を生み出してしまいます。現場で絶対にやってはいけない注意点をまとめました。
1. JITコンパイルのオーバーヘッドを無視する
.NETのコードは、最初に実行されるときにマシン語に翻訳(JITコンパイル)されます。そのため、「1回目の計測」は必ず遅くなります。 正確な測定をしたい場合は、本番計測の前に1回「ダミーの空打ち(ウォームアップ)」を入れておくのがプロの作法です。
2. DebugビルドとReleaseビルドを混同する
Visual Studioで「デバッグ実行(F5)」しているときは、裏でデバッグ用の余計な監視コードが動いているため、パフォーマンスが本来の性能を発揮しません。必ず「Releaseビルド」にして、IDEなし(exe単体)で実行した状態で計測しましょう。
3. ループの中での無駄なインスタンス化
計測のたびに `New Stopwatch()` をループ内で回すのはメモリの無駄です。計測対象の外側で1つだけインスタンスを生成し、`Restart()` で使い回すのがスマートです。
—
まとめ
今回は `Stopwatch` クラスを用いて、VB.NETで高精度な処理時間を計測し、ボトルネックをあぶり出す手法を解説しました。
- 「DateTime.Now」は捨てて、「Stopwatch」を使え!
- CPUのタイマーを利用しているから、マイクロ秒単位で正確に測れる!
- 比較検証には `sw.Restart()` をスマートに活用せよ!
「なんとなく遅い気がする」という感覚の世界から脱却し、数字という絶対的な根拠を持ってコードを改善できるようになると、プログラミングが何倍も楽しく、そして誇らしいものになります。
ここをクリアすれば、あなたのVB.NETの基礎力とパフォーマンスチューニングのスキルは、確実に現場のエース級に近づいていますよ。さあ、明日からのコードに早速取り入れてみましょう!
