VBで速度比較(Withステートメント)

ひとつのオブジェクトやらユーザー定義型をまとめて処理するときWithステートメントを使えば速いと聞いたことがありますが、実際のところどうなのか、調べてみました。

ユーザー定義型で計測

まずはこんなコードで試してみました。

' ユーザー定義型の定義と宣言Private Type AB As Long: C As Long: D As Long: E As Long: F As LongG As Long: H As Long: I As Long: J As Long: K As LongL As Long: M As Long: O As Long: P As Long: Q As LongR As Long: S As Long: T As Long: U As Long: V As LongEnd Type    ' Nがないのはただの入力ミスですDim Z As A
' Withあり計測For I = 1 To NWith Z.B = 1...End WithNext
' Withなし計測For I = 1 To NZ.B = 1...Next
回数速い方倍率左の表の読み方ですが、回数はZの要素に値を代入した回数で、5回ならFまで代入したということで、速い方・倍率はそのままです。
念のため言っておけば、あり・なしというのは、Withあり・Withなしの意味ですよ。

なんなのでしょうか、この結果は。
確かに1回の時には通常より遅くなることがあるというのは感覚的にもわかります。
しかしこの結果が表しているのは、12回以上は使わないとかえって遅くなるという事実です。
そして、たとえ12回以上使っても1割の高速化がやっとです。
下手に使って1割以上時間をかけてしまうリスクを考えると、数えるほどしか処理を行わない場面では使わないほうがよさそうです。

1回なし2.24
2回なし1.83
3回なし1.57
4回なし1.36
5回なし1.29
6回なし1.21
7回なし1.16
8回なし1.12
9回なし1.06
10回なし1.06
11回なし1.02
12回-1.00
13回あり1.02
14回あり1.03
15回あり1.05
16回あり1.07
17回あり1.06
18回あり1.09
19回あり1.10
20回あり1.10

納得がいかないのでWithを外に出して計測。

' Withあり計測With ZFor I = 1 To N.B = 1...NextEnd With
' Withなし計測For I = 1 To NZ.B = 1...Next
回数速い方倍率ほぼ期待通りの結果が出ました。
このような使い方の時には3割程度の高速化が期待できるようです。
少ない回数で効果が落ちているのは、恐らく関係ない変数Iにアクセスする割合が増えているからなのでしょう。
1回あり1.20
2回あり1.18
3回あり1.21
4回あり1.25
5回あり1.25
6回あり1.27
7回あり1.24
8回あり1.27
9回あり1.27
10回あり1.28
11回あり1.27
12回あり1.29
13回あり1.29
14回あり1.30
15回あり1.29
16回あり1.30
17回あり1.29
18回あり1.30
19回あり1.29
20回あり1.30

コントロールで計測

今度はHScrollBarコントロールで試してみました。
「I And 16383」の影響で数%遅くなっていますが大きな影響はないと思います。

' Withあり計測For I = 1 To NWith HScroll1.Value = I And 16383...End WithNext
' Withなし計測For I = 1 To NHScroll1.Value = I And 16383...Next
回数速い方倍率今度は2回目で早くも効果が現れましたが、その効果の大きさそのものはごくわずかです。
「I And 16383」で5%ほど遅くなっていることを考えると、この違いはほぼ誤差の範囲内と考えても構わないくらい小さなものだと思われます。
1回なし1.03
2回あり1.02
3回あり1.02
4回あり1.02
5回あり1.02
6回あり1.04
7回あり1.04
8回あり1.03
9回あり1.04
10回あり1.04

やはりWithを外に出してみます。

' Withあり計測With HScroll1For I = 1 To N.Value = I And 16383...NextEnd With
' Withなし計測For I = 1 To NHScroll1.Value = I And 16383...Next
回数速い方倍率先程ほとんど効果が現れなかった理由が分かる気がします。
速くなるには速くなるのですが、たったの4%です。
多分Valueをいちいち変更している影響でしょうが、コントロールの場合、もっともっと重たい処理はいくらでもあるので、他の場合では効果はもっと薄いと考えてもよさそうです。
1回あり1.04
2回あり1.04
3回あり1.05
4回あり1.04
5回あり1.03
6回あり1.04
7回あり1.03
8回あり1.03
9回あり1.03
10回あり1.04

総合して

これらの結果を見ると、どうやらよほどたくさんの処理を行わない限り、Withステートメントそのものの実行時間のため、効果が帳消しにされてしまうようです。
だから、ループを使って何十回も何百回も繰り返し使うケースなどでは処理速度のために使う価値があるにしても、通常の処理の中で使う分にはコードを見やすくして量を減らすくらいに認識しておいたほうがよいでしょう。