こんにちは、すーみんです。この春からエンジニアになった新米プログラマ、遂にQiita初投稿です
どうぞよろしくお願いしますm(*_ _)m
#プロローグ:分岐1つで処理は早くなる
ある日、先輩とペアプロをしていた際に、私は下のようなコードを書いていました。
For i = 1 To cnt
If arr(i) = hoge Then
'なんかの処理
End If
If arr(i) = fuga Then
'なんかの処理
End If
Next i
するとボクはこんなことを言われました。
「この書き方だと大規模データに弱くなるよ。」
そして先輩は次のコードを提示しました。
For i = 1 To cnt
If arr(i) = hoge Then
'なんかの処理
ElseIf arr(i) = fuga Then
'なんかの処理
End If
Next i
if文の連続より、ElseIfで連続するほうが「判定処理が少なくなる」。
そう、先輩は教えてくれました。
なるほど確かに、ちょっと考えればわかることです。しかし具体的にどれくらい変わるのでしょう。気になったので調べてみました。
#じっけん!
環境は以下のとおりです。
項目 | |
---|---|
OS | Windows 10 64bit |
メモリ | 8GB |
CPU | intel Core i5-7500 第7世代 |
Excel | Office 365 (VBA 7.0) |
##ソースコード
計測用に1000万個のデータを下記のソースを使ってCollection
に格納し、For Each
で1000万個のデータに対してそれぞれIf分岐を実施しています。
ソースコードは以下のとおりです。
'If - ElseIf 2分岐の場合
Sub Example1()
Dim i As Long
Dim arr As Collection
Dim ifA As Long
Dim ifB As Long
Dim t As Double
Dim item As Variant
Set arr = New Collection
For i = 1 To 10000000
arr.Add (i Mod 3)
Next i
ifA = 0
ifB = 0
'計測対象
t = Timer
For Each item In arr
'分岐A
ifA = ifA + 1
If item = 0 Then
GoTo continue
'分岐B
ElseIf item = 1 Then
ifB = ifB + 1
GoTo continue
End If
continue:
Next
Debug.Print ("処理時間:" & Timer - t & "秒")
Debug.Print ("分岐A:" & ifA & "回")
Debug.Print ("分岐B:" & ifB & "回")
End Sub
'If - ElseIf 3分岐の場合
'長くなるのでFor Each の中のみ
For Each item In arr
'分岐A
ifA = ifA + 1
If item = 0 Then
GoTo continue
'分岐B
ElseIf item = 1 Then
ifB = ifB + 1
GoTo continue
'分岐C
ElseIf item = 2 Then
ifC = ifC + 1
GoTo continue
End If
continue:
Next
また、If - If のElseを使わない方法を実行するため、For Each
の中は、それぞれ下記のように書き換えて使用しています。
'If - If 2分岐の場合
'分岐A
For Each item in arr
ifA = ifA + 1
If item = 0 Then
GoTo continue
End If
'分岐B
ifB = ifB + 1
If item = 1 Then
GoTo continue
End If
continue:
Next
'If - If 3分岐の場合
For Each item In arr
'分岐A
ifA = ifA + 1
If item = 0 Then
GoTo continue
End If
'分岐B
ifB = ifB + 1
If item = 1 Then
GoTo continue
End If
'分岐C
ifC = ifC + 1
If item = 2 Then
GoTo continue
End If
continue:
Next
微妙にコードが違う気がしますが…気にしないでいきましょう()
##計測結果
###比較表
(処理時間は1000分の1秒で四捨五入しています)
分岐タイプ | 2分岐 | 3分岐 |
---|---|---|
If - ElseIf | 0.578 sec. | 0.640 sec. |
If - If | 0.625 sec. | 0.714 sec. |
###出力結果
'2分岐
If - elseIf の場合
処理時間:0.578125秒
分岐A:10000000回
分岐B:3333334回
If - If の場合
処理時間:0.625秒
分岐A:10000000回
分岐B:6666667回
'3分岐
If - ElseIf の場合
処理時間:0.640625秒
分岐A:10000000回
分岐B:3333334回
分岐C:3333333回
If - If の場合
処理時間:0.71484375秒
分岐A:10000000回
分岐B:6666667回
分岐C:3333333回
比較表を見ての通り、2分岐では両者に約0.05秒、3分岐では約0.07秒の差が確認できました。
また、処理回数も出力結果から分かる通り、分岐Bを通った回数にも差があることが確認できます。約330万データの分岐を省略できた分、ElseIfを使用するほうが早かったように思われます。
#まとめ
今回の例では330万データをただ分岐するだけでしたが、場合によってはここで入出力処理を行ったり、データベースにクエリを発行したり、とコストの高い処理を行うこともあるかもしれません。そうなると、ただ分岐するだけで0.07秒の差は大きくなるような気がします。
可能な限り、分岐の数を少なく、ですね
ご指摘等ございましたら、コメントください。よろしくお願いします。