Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


5594 / 13645 ツリー ←次へ | 前へ→

【49945】書き出し処理速度について じょじょ 07/6/29(金) 23:11 質問[未読]
【49948】Re:書き出し処理速度について neptune 07/6/30(土) 9:34 発言[未読]
【49950】Re:書き出し処理速度について Hirofumi 07/6/30(土) 9:53 発言[未読]
【49952】Re:書き出し処理速度について Hirofumi 07/6/30(土) 10:04 発言[未読]
【49953】Re:書き出し処理速度について neptune 07/6/30(土) 11:17 発言[未読]
【49972】Re:書き出し処理速度について じょじょ 07/7/1(日) 15:41 お礼[未読]
【49975】Re:書き出し処理速度について neptune 07/7/1(日) 16:51 発言[未読]
【49976】Re:書き出し処理速度について Hirofumi 07/7/1(日) 20:06 発言[未読]
【49978】Re:書き出し処理速度について neptune 07/7/1(日) 22:51 発言[未読]
【49982】Re:書き出し処理速度について ichinose 07/7/1(日) 23:36 発言[未読]

【49945】書き出し処理速度について
質問  じょじょ  - 07/6/29(金) 23:11 -

引用なし
パスワード
   バイナリデータを読み込み、数値データに変換、テキストファイルにタブ区切りで書き出すプログラムをvba/excelにて作成中ですが、書き出し処理速度の遅さに困惑しております。数値データに変換した配列はDATA(256,120000)としており、書き出しデータ数は約3,000,000個あります。その書き出しプログラムを下記のように記述したのですが、とんでもなく処理速度がおそいのです。
Open "c:\test.txt" For Output As #2
For i = 1 To 120000
 For j = 1 To 256
  Print #2, DATA(j, i); Chr(9);
 Next j
 Print #2, Chr(10);
Next i
Close #2
対処方法をご存知でしたら、ご教授願います。

【49948】Re:書き出し処理速度について
発言  neptune  - 07/6/30(土) 9:34 -

引用なし
パスワード
   こんにちは

処理速度が遅いのはHDDへ物理的に書きにいっている回数が多いからでは
ないでしょうか?

そこで、変数に収めてしまって、その回数を出来る限り減らせば
速くなると思いますが、どうでしょう?
検証なしで発言してますが、かなり効果はあるような気がします。?

【49950】Re:書き出し処理速度について
発言  Hirofumi  - 07/6/30(土) 9:53 -

引用なし
パスワード
   何を持って遅いのか?、速いのか?善く解りませんが?
書き出す部分が遅いのでは無く、全体を見直した方が善いような気がします

>数値データに変換した配列はDATA(256,120000)としており、

大きな配列変数を確保していると、リソース不足に成りスワップ等が発生して
処理全体が遅く成ると思いますので

>  バイナリデータを読み込み、数値データに変換、

の部分を一括して配列に格納するのでは無く、
どうやって、変換しているのかコードが解ら無いので何とも言えませんが?
出来れば行単位の処理にした方が、幾らか速く成ると思います

また、

>Open "c:\test.txt" For Output As #2
>For i = 1 To 120000
> For j = 1 To 256
>  Print #2, Data(j, i); Chr(9);
> Next j
> Print #2, Chr(10);
>Next i
>Close #2

ですが、書き込み処理と、文字列の連結とでは(どちらも時間が掛る?)、
文字列の連結の方が、まだましな様な気がしますので、以下の様にして見ては?

  Dim strBuff As String
  
  Open "c:\test.txt" For Output As #2
  
  For i = 1 To 120000
    strBuff = Data(1, i)
    For j = 2 To 256
      strBuff = strBuff & vbTab & Data(j, i)
    Next j
    strBuff = strBuff & vbLf
    Print #2, strBuff
  Next i
  
  Close #2

【49952】Re:書き出し処理速度について
発言  Hirofumi  - 07/6/30(土) 10:04 -

引用なし
パスワード
   あ!いけね!
出力部分が違っていた

Print #2, strBuff

では無く

Print #2, strBuff;

です

【49953】Re:書き出し処理速度について
発言  neptune  - 07/6/30(土) 11:17 -

引用なし
パスワード
   こんにちは

文字列の連結ですが、test1とtest2を比較してみて下さい。test2が圧倒的に
速いです。
test1:連結
test2:あらかじめ領域を確保しておき、置換する

Option Explicit
Private Declare Function timeGetTime Lib "winmm.dll" () As Long

Private T1 As Long
Private T2 As Long

Sub test1()
Dim a As String
Dim sbuf As String
Dim i As Long

  a = "今日は暑いぞ!123456789"
  sbuf = ""
  T1 = timeGetTime()
  For i = 0 To 10000
    sbuf = sbuf & a
  Next i
  T2 = timeGetTime()
  Debug.Print "Size = " & Len(sbuf) & "  処理時間" & vbTab & (T2 - T1) / 1000 & " Sec"
End Sub

Sub test2()
Dim a As String
Dim sbuf As String
Dim i As Long, lLen As Long
Dim lStart As Long

  a = "今日は暑いぞ!123456789"
  lLen = Len(a)
  sbuf = Space(320016) 'この320016はあらかじめ文字数を計りました。
             '実用では算出できると思います。
  T1 = timeGetTime()
  For i = 0 To 20000
    If i <> 0 Then
      lStart = lLen * i
    Else
      lStart = 1
    End If
    Mid(sbuf, lStart, lLen) = a
  Next i
  T2 = timeGetTime()
  Debug.Print "Size = " & Len(sbuf) & "  処理時間" & vbTab & (T2 - T1) / 1000 & " Sec"
End Sub

まぁ、物理的な書き込みの方が効果はあると思いますが、
更に高速化したい場合検討してみてください。

【49972】Re:書き出し処理速度について
お礼  じょじょ  - 07/7/1(日) 15:41 -

引用なし
パスワード
   皆様
hirofumiさんの提案どうり実行してみると劇的に速くなりました。
本当にありがとうございました。
そこでさらに質問ですが、今回は1行ごとに書き出しを実施しましたが、
全部の行を一気に書き出すことを考えましたが、うまくいきませんでした。
やはり、1行ごとに処理しないと無理なのかな?

▼Hirofumi さん:
>  Dim strBuff As String
>  
>  Open "c:\test.txt" For Output As #2
>  
>  For i = 1 To 120000
>    strBuff = Data(1, i)
>    For j = 2 To 256
>      strBuff = strBuff & vbTab & Data(j, i)
>    Next j
>    strBuff = strBuff & vbLf
>    Print #2, strBuff
>  Next i
>  
>  Close #2

【49975】Re:書き出し処理速度について
発言  neptune  - 07/7/1(日) 16:51 -

引用なし
パスワード
   ▼じょじょ さん:

>そこでさらに質問ですが、今回は1行ごとに書き出しを実施しましたが、
>全部の行を一気に書き出すことを考えましたが、うまくいきませんでした。
どのようなソースで、どこかどううまくいかなかったのかがわからない。
必要な情報は出さないと。

後、文字連結のサンプルは見ましたか?
せっかく書いたのに参考にしてほしいなぁ。。

【49976】Re:書き出し処理速度について
発言  Hirofumi  - 07/7/1(日) 20:06 -

引用なし
パスワード
   >hirofumiさんの提案どうり実行してみると劇的に速くなりました。
>本当にありがとうございました。
>そこでさらに質問ですが、今回は1行ごとに書き出しを実施しましたが、
>全部の行を一気に書き出すことを考えましたが、うまくいきませんでした。
>やはり、1行ごとに処理しないと無理なのかな?

言いたかった事は、確かにTextFileに書き出す部分も含むのですが?
一番、影響が大きいのは、

>数値データに変換した配列はDATA(256,120000)としており、

の部分だと思います
そこで、「1行単位(レコード単位)にした方が善いのでは?」と言うのは
バイナリーファイルを1レコード分読み込んで変換し、大きい配列に貯めずに
直ぐ1レコード分のCSVで出力しては如何でしょうか?と言う事です
こちらは、やって見ましたか?

なぜ、

>全部の行を一気に書き出すことを考えましたが、うまくいきませんでした。

一気に出力しなければならないのですか?
やるとしたら、変数(配列では無く)に文字列として貯えて出力する様ですが?
多分、それほど速くは成らない様な気がします?

こう言うのって、OS、Excelのヴァージョン、リソースの量、データの量で
処理のバランスが変わってくるので、
一概に一気に読み込んで、一気に書き込むが常に善い事とは思っていませんが?

【49978】Re:書き出し処理速度について
発言  neptune  - 07/7/1(日) 22:51 -

引用なし
パスワード
   ▼Hirofumi さん:
こんにちは
>言いたかった事は、確かにTextFileに書き出す部分も含むのですが?
>一番、影響が大きいのは、
>
>>数値データに変換した配列はDATA(256,120000)としており、
>の部分だと思います
気になったので検証してみたんですが、そのとおりみたいですね。
配列の大きさですね。
Win95,98の頃に比べてCPU、メモリ搭載量など、マシンスペックが大きく
変わってきてますので、HDDへの読み出し、書き込みではさほど体感的に
感じないようです。

>こう言うのって、OS、Excelのヴァージョン、リソースの量、データの量で
>処理のバランスが変わってくるので、
>一概に一気に読み込んで、一気に書き込むが常に善い事とは思っていませんが?
昔、Wind98でやった時は、一気読み込み、書き出しが早かったです。
これは、10MB程度まではという条件付です。これを大きく超えると
複数回に分けての分割読み込み、書き出しが速かったです。
これはマシンスペック、O/Sに依存するところが大きかったと思います。

現在でもデータにもよると思いますが、数10MB程度では一気の方が速いことは
速いみたいです。(30MB程度までしかやってませんが)

Excelのバージョンですが、VBAでの処理になるとExcel97以降は
になると、殆ど同じようなものですからあんまり影響は
ないのではないでしょうか?

いずれにしても、以下に配列要素数を少なくし、文字列処理を速くするか
で劇的に変わってくるしょうね。

それにしても、ファイルサイズはどれくらいなんでしょう?

【49982】Re:書き出し処理速度について
発言  ichinose  - 07/7/1(日) 23:36 -

引用なし
パスワード
   こんばんは。
興味深いご質問ですね!!

じょじょさんが投稿された配列DATA()の型は何でしょうか?
数値データと書かれていることから推測すると、数値型の配列ということですか?
(Long、Single、Double)
新規ブックの標準モジュールにて

以下のコードを実行してその処理速度を比べてみてください。

(必ず、一度、ブックを保存した後に実行してください)

'============================================================
Sub test1()
  Dim i, j
  Dim st As Double
  Dim data(1 To 256, 1 To 120000) As Long
  For i = 1 To 120000
    For j = 1 To 256
     data(j, i) = Int(Rnd() * 254) + 1
     Next j
    Next i
  MsgBox "サンプルデータの準備完了" & vbCrLf & "これから、ファイルの書き込みを行います"
  st = [now()]
  Open ThisWorkbook.Path & "\test.txt" For Output As #2
  For i = 1 To 120000
    For j = 1 To 256
     Print #2, data(j, i); Chr(9);
     Next j
    Print #2, Chr(10);
    Next i
  Close #2
  MsgBox "処理時間 : " & Format([now()] - st, "hh:mm:ss")
End Sub
'======================================================================
Sub test2()
  Dim i, j
  Dim st As Double
  Dim data(1 To 256, 1 To 120000) As Long
  For i = 1 To 120000
    For j = 1 To 256
     data(j, i) = Int(Rnd() * 254) + 1
     Next j
    Next i
  MsgBox "サンプルデータの準備完了" & vbCrLf & "これから、ファイルの書き込みを行います"
  st = [now()]
  Open ThisWorkbook.Path & "\test.txt" For Output As #2
  For i = 1 To 120000
    For j = 1 To 256
     Print #2, CStr(data(j, i));Chr(9);
     Next j
    Print #2, Chr(10);
    Next i
  Close #2
  MsgBox "処理時間 : " & Format([now()] - st, "hh:mm:ss")
End Sub
'======================================================================
Sub test3()
  Dim i, j
  Dim st As Double
  Dim data(1 To 256, 1 To 120000) As Long
  For i = 1 To 120000
    For j = 1 To 256
     data(j, i) = Int(Rnd() * 254) + 1
     Next j
    Next i
  MsgBox "サンプルデータの準備完了" & vbCrLf & "これから、ファイルの書き込みを行います"
  st = [now()]
  Open ThisWorkbook.Path & "\test.txt" For Output As #2 Len = 5120
  For i = 1 To 120000
    For j = 1 To 256
     Print #2, CStr(data(j, i)); Chr(9);
     Next j
    Print #2, Chr(10);
    Next i
  Close #2
  MsgBox "処理時間 : " & Format([now()] - st, "hh:mm:ss")
End Sub

test1,test2,test3の順に処理時間は短縮されています。

特にtest1とtest2の処理時間差は顕著です。

何故かというと、test1とtest2では、作成するファイル容量が違うからです。

数値データに対して、

Print #2,data;

とした場合、データの前後に空白が書き込まれます

空白123空白Tab空白222空白

のように。

対して、test2の文字列データに変換後の書き込みでは、空白が書き込まれません。

123Tab222

というように

作成されるファイルが小さいのですから、処理時間が速いのです。

test3では、バッファサイズを設定してみました。

微量ですが、処理時間が短縮されています。

試してみてください。

5594 / 13645 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free