和風スパゲティのレシピ

日本語でコーディングするExcelVBA

マクロの実行時間計測(Timer)をクラス化する

マクロの実行時間はTimer関数で0.00秒単位で測ることができます。

Dim 開始時刻 As Double, 終了時刻 As Double
開始時刻 = Timer

 ここに時間のかかる処理

終了時刻 = Timer
Debug.Print "このマクロの実行時間:" & (終了時刻 - 開始時刻) & "秒"

これでも十分に簡単なコードですが、
もっと簡単に使えるようクラスにしてみましょう。


10数行しかないとても簡単なクラスですので、
クラスモジュールの練習台にもどうぞ。

Timer関数による実行時間計測を行うマクロ

実行サンプル

以下の様にCallするだけで各工程の時間を測定できるようなクラスを作成します。

Sub サンプルマクロ()

    Dim cls時間計測 As Class実行時間計測
    Set cls時間計測 = New Class実行時間計測

    ' 処理A
    処理A1
    処理A2
    処理A3
    Call cls時間計測.DebugPrint経過時間
    
    ' 処理B
    処理B1
    処理B2
    処理B3
    Call cls時間計測.DebugPrint経過時間
    
    ' 処理C
    処理C1
    処理C2
    処理C3
    Call cls時間計測.DebugPrint経過時間
    
End Sub

時間計測クラスの実行サンプル

これで処理Cが一番遅いというのがわかりましたね。


ついでに表示テキストの設定機能も付けておきましょう。

' テキストを渡した場合はそのように表示してくれる
処理A1
処理A2
処理A3
Call cls時間計測.DebugPrint経過時間("処理A")

処理B1
処理B2
処理B3
Call cls時間計測.DebugPrint経過時間("処理B")

処理C1
処理C2
処理C3
Call cls時間計測.DebugPrint経過時間("処理C")

処理名の表示機能サンプル

処理が多くてわからなくなりそうなら指定すればよいし、
面倒なら指定しなければ「実行時間:」で表示してくれる仕様です。



最低限の機能というとこのあたりですかね。

ではこのクラスを作りましょう。

ソースコード

クラスモジュール名を「Class実行時間計測」としてください。

Private sec開始時刻 As Single

Sub DebugPrint経過時間(Optional 表示テキスト As String = "実行時間")
    Debug.Print 表示テキスト & ":" & GetSec経過時間 & "秒"
    sec開始時刻 = Timer
End Sub

Function GetSec経過時間() As Single
    GetSec経過時間 = WorksheetFunction.RoundDown(Timer - sec開始時刻, 2)
End Function

Private Sub Class_Initialize()
    sec開始時刻 = Timer
End Sub

解説

1プロパティ3メソッドの非常に簡単なクラスです。

開始時間をクラス内にプロパティ変数として持っておき、
Debug.Print が実行されるたびに表示と値の更新を行っています。


前述の通り、表示するテキストはOptionalキーワードで省略可能にしています。



また最初のスタートについては、クラスをNewした際に自動で始まるよう、
Initializeプロシージャで初期値をセットしています。

このおかげでSetと同時に計測が始まってくれますが、注意点として、

Dim cls時間計測 New Class実行時間計測

このDimとNewを同時に行う書き方ではスタートしてくれません。


この場合のInitialize実行タイミングは最初にこのクラスが参照されたとき
すなわち

Call cls時間計測.DebugPrint経過時間("処理A")

ここになりますので、これでは処理Aの実行時間は常に0になってしまいます。


DimとNewを同時に行う書き方に慣れている方は、クラスの中身を

Private sec開始時刻 As Single

Sub DebugPrint経過時間(Optional 表示テキスト As String = "実行時間")
    Debug.Print 表示テキスト & ":" & GetSec経過時間 & "秒"
    sec開始時刻 = Timer
End Sub

Function GetSec経過時間() As Single
    GetSec経過時間 = WorksheetFunction.RoundDown(Timer - sec開始時刻, 2)
End Function

Sub 計測を開始する()
    sec開始時刻 = Timer
End Sub

と、計測開始をInitializeプロシージャから通常プロシージャに変更し、

Dim cls時間計測 New Class実行時間計測
Call cls時間計測.計測を開始する

でスタートしても良いと思います。

どちらも2行はかかるわけですしね。



こんな簡単なクラスでもメインコードをかなり綺麗にしてくれる効果があります。


実行計測に活用するのはもちろんのこと、
クラスモジュールの練習台にも使ってみてください。

クラスモジュールの基本についてはこちらをどうぞ。
www.limecode.jp


総実行時間を計測したい場合

例えば「総実行時間」を表示したい場合は、
クラスモジュールの中身を

Private secクラス開始時刻 As Single
Private sec開始時刻 As Single

Sub DebugPrint経過時間(Optional 表示テキスト As String = "実行時間")
    Debug.Print 表示テキスト & ":" & GetSec経過時間 & "秒"
    sec開始時刻 = Timer
End Sub
Function GetSec経過時間() As Single
    GetSec経過時間 = WorksheetFunction.RoundDown(Timer - sec開始時刻, 2)
End Function

Sub DebugPrintクラス開始からの経過時間(Optional 表示テキスト As String = "総実行時間")
    Debug.Print 表示テキスト & ":" & GetSecクラス開始からの経過時間 & "秒"
    sec開始時刻 = Timer
End Sub
Function GetSecクラス開始からの経過時間() As Single
    GetSecクラス開始からの経過時間 = WorksheetFunction.RoundDown(Timer - secクラス開始時刻, 2)
End Function

Private Sub Class_Initialize()
    secクラス開始時刻 = Timer
    sec開始時刻 = Timer
End Sub

このように書き換えればOKです。

変数をひとつ増やして、対応する表示プロシージャを作っただけですね。


最初は「総実行時間」という命名でプロパティとメソッドを作ったのですが、
実行時間と名前が似すぎて危険なので、選び間違い対策に名前を長くしてみました。

1度しか使わないメソッドですし、長くても問題ありませんからね。


最初に紹介したクラスは最低限の機能に絞っていましたが、
クラスはカスタマイズのしやすさもメリットのひとつです。


自分がよくやる処理に応じて、カスタマイズしてみてください。