8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

分岐処理、速度ってどう変わる?

Posted at

 こんにちは、すーみんです。この春からエンジニアになった新米プログラマ、遂にQiita初投稿です:beginner:
 どうぞよろしくお願いします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秒の差は大きくなるような気がします。

 可能な限り、分岐の数を少なく、ですね:slight_smile:


ご指摘等ございましたら、コメントください。よろしくお願いします。

8
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?