2009/05/18

String型の連結-VBA編

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

(1)
For i = 0 To lngMax
    strText1 = strText1 & "あいうえおかきくけこさしすせそ"
Next
(2)
For i = 0 To lngMax
    strText2 = strText2 & "あいうえおかきくけこさしすせそ"
    If Len(strText2) > 3000 Then strText1 = strText1 & strText2: strText2 = vbNullString
Next
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編」参照。

Dim clsTimerMM As clsTimerMM
Dim strTextMsg As String
'************************
Dim strMsg As String
Dim strText1 As String
Dim strText2 As String
Dim lngMax As Long
Dim i As Long
'************************
Set clsTimerMM = New clsTimerMM
strMsg = "あいうえおかきくけこさしすせそ"

lngMax = 10000
'************************
clsTimerMM.SetStartDate
For i = 0 To lngMax
    strText1 = strText1 & strMsg
Next
strTextMsg = "(1):" & clsTimerMM.ElapsedTime & vbCrLf
Me.txtText1.Value = strText1 & vbCrLf
strText1 = vbNullString
'************************
clsTimerMM.SetStartDate
For i = 0 To lngMax
    strText2 = strText2 & strMsg
    If Len(strText2) > 3000 Then strText1 = strText1 & strText2: strText2 = vbNullString
Next
If Len(strText2) Then strText1 = strText1 & strText2
strTextMsg = strTextMsg & "(2):" & clsTimerMM.ElapsedTime & vbCrLf
Me.txtText2.Value = strText1 & vbCrLf

Me.txtDATA.Value = strTextMsg
Set clsTimerMM = Nothing

0 件のコメント: