2009/05/18

String型の連結-VBA編

今回は「VB6.0やVBAだとこういう書き方もアリなんだー」という、個人的には目から鱗ネタです。下記のソース、(1)と(2)、どちらが速いか?というわけですね。

(1)
  1. For i = 0 To lngMax  
  2.     strText1 = strText1 & "あいうえおかきくけこさしすせそ"  
  3. Next  
(2)
  1. For i = 0 To lngMax  
  2.     strText2 = strText2 & "あいうえおかきくけこさしすせそ"  
  3.     If Len(strText2) > 3000 Then strText1 = strText1 & strText2: strText2 = vbNullString  
  4. Next  
  5. If Len(strText2) Then strText1 = strText1 & strText2  

(1)の方が一般的な書き方だと思いますが、この場合、(2)の方が圧倒的に速いのです。

結果

(1):343 ミリ秒

(2):16 ミリ秒

※Acceess2003で実験

VB6.0のString型は値型なので文字列を追加する度に、データの文字列をコピーしているわけですね。コピーするものが、長ければ長いほど、コピーの作業にコストがかかる。

ひるがえって(2)ではstrText2にちまちま文字列を追加して、 If Len(strText2) > 3000 のタイミングでstrText1に突っ込んで、strText2をカラッポにしてまた文字列をためていく。その方が、長い文字列をコピーする回数が激減して、処理が速くなるというわけなんですね(ちなみに.Netだとstring型は一応参照型なので、文字列をセットする度にコンストラクタが発生している様子でVB6.0/VBAどころではない負荷を、もはや「体感」として感じます。なのでStringBuilderのインデクサで対応)。

サンプルソース

フォームにtxtDATAという名前のテキストボックスを作って、そこにタイムを表示する。clsTimerMMクラスは「時間経過計測クラス‐VBA編」参照。

  1. Dim clsTimerMM As clsTimerMM  
  2. Dim strTextMsg As String  
  3. '************************  
  4. Dim strMsg As String  
  5. Dim strText1 As String  
  6. Dim strText2 As String  
  7. Dim lngMax As Long  
  8. Dim i As Long  
  9. '************************  
  10. Set clsTimerMM = New clsTimerMM  
  11. strMsg = "あいうえおかきくけこさしすせそ"  
  12.   
  13. lngMax = 10000  
  14. '************************  
  15. clsTimerMM.SetStartDate  
  16. For i = 0 To lngMax  
  17.     strText1 = strText1 & strMsg  
  18. Next  
  19. strTextMsg = "(1):" & clsTimerMM.ElapsedTime & vbCrLf  
  20. Me.txtText1.Value = strText1 & vbCrLf  
  21. strText1 = vbNullString  
  22. '************************  
  23. clsTimerMM.SetStartDate  
  24. For i = 0 To lngMax  
  25.     strText2 = strText2 & strMsg  
  26.     If Len(strText2) > 3000 Then strText1 = strText1 & strText2: strText2 = vbNullString  
  27. Next  
  28. If Len(strText2) Then strText1 = strText1 & strText2  
  29. strTextMsg = strTextMsg & "(2):" & clsTimerMM.ElapsedTime & vbCrLf  
  30. Me.txtText2.Value = strText1 & vbCrLf  
  31.   
  32. Me.txtDATA.Value = strTextMsg  
  33. Set clsTimerMM = Nothing  

0 件のコメント: