tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板
VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板
[ツリー表示へ]  [ワード検索]  [Home]

タイトル Re^4: 容量が増えると動作速度が遅くなる
投稿日: 2009/07/31(Fri) 22:05
投稿者魔界の仮面弁士
> みなさんのご意見お願いいたします。

ループ内で行われている
 write_data = write_data & data1 & "," & data3 & "," & data2 & vbCrLf
の部分を
 write_data = write_data & (data1 & "," & data3 & "," & data2 & vbCrLf)
にするだけで、処理効率がアップしますよ。(理由は後述します)


しかし、もっと効率の良い方法があります。
それは既に No.13914 で YuO さんが回答している方法なのですが、
出力ファイルと入力ファイルを同時に開いて、順次書きこんでいくという物です。

つまり、現在の

    fData = FreeFile()
  Open 入力ファイル For Input Access Read As #fData
  Do Until EOF(fData)
    Input #fData, data1, data2, data3
        write_data = write_data & data1 & "," & data3 & "," & data2 & vbCrLf
    Loop
    Close #fData
    fData = FreeFile()
    Open fName For Output Access Write As #fData
    Print #fData, write_data
    Close #fData

のような処理を、

    fIn = FreeFile()
  Open 入力ファイル For Input Access Read As #fIn
    fOut = FreeFile()
    Open 出力ファイル For Output Access Write As #fOut
  Do Until EOF(fIn)
    Input #fIn, data1, data2, data3
    Print #fOut, data1 & "," & data3 & "," & data2
    Loop
    Close #fIn, #fOut

という形式にするという物です。これにより、相当の高速化が期待できます。



> 下の通りデータを並べ替えているので一気にバイナリで読んで書き込むこともできないので
> あきらめました。

文字列連結を行うと、そのたびに
  新たな文字列領域の確保 → 確保された領域へのコピー → 以前の領域を破棄
という作業が繰り返し行われる事になります。

短い文字列同士の連結であれば、確保サイズが小さいため、さほど時間はかからないのですが、
長い文字列に対して連結する場合には、この確保と解放にかかる時間が問題となります。


そこで、「長い文字列」に対して文字列を連結させる回数を減らす工夫が必要です。


ひとつ実験。下記を試してみてください。

Private Sub Command1_Click()
    Dim T As Single, L As Long, S As String
    T = Timer
    For L = 1 To 10000
        S = S & CStr(L) & "TEST"
    Next
    Debug.Print Format(Timer - T, "#,0.000秒")
End Sub

Private Sub Command2_Click()
    Dim T As Single, L As Long, S As String
    T = Timer
    For L = 1 To 10000
        S = S & (CStr(L) & "TEST")
    Next
    Debug.Print Format(Timer - T, "#,0.000秒")
End Sub


いずれも同じ処理を行っています。違うのは、文字列連結部分を
  S = S &  CStr(L) & "TEST"       'Command1
    S = S & (CStr(L) & "TEST")      'Command2
にしているだけです。

両者は当然、同じ文字列を生成しますが、後者の方が高速に処理されます。
実際、これを当方環境で試してみると、平均時間で
      ループ 10000 回        20000 回       30000 回
  Command1 …… 約0.6秒 …… 約3.8秒 …… 約10.8秒
  Command2 …… 約0.3秒 …… 約1.8秒 …… 約5.3秒
という速度差になりました。処理時間がほぼ半分になっていますね。


これは Command1 の方の処理が
                          '『S = S & CStr(L) & "TEST"』
  X = S & CStr(L)      ' S が大きいので、処理に時間がかかる
  S = X & "TEST"        ' X が大きいので、処理に時間がかかる

に相当する処理が行われているのに対し、Command2 の方では
                          '『S = S & (CStr(L) & "TEST")』
  X = CStr(L) & "TEST" ' 短い文字列なので、処理時間が短い
  S = S & X             ' S が大きいので、処理に時間がかかる

という処理になるためです。そのため、処理時間を約半分で済ませることができます。


そしてこれが先の
 'write_data = write_data & data1 & "," & data3 & "," & data2 & vbCrLf
 write_data = write_data & (data1 & "," & data3 & "," & data2 & vbCrLf)
という修正案を提示した理由となります。

- 関連一覧ツリー をクリックするとツリー全体を一括表示します)

古いスレッドにレスはつけられません。