C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[15]: CSVファイル入出力時の速度向上方法について


(過去ログ 80 を表示中)

[トピック内 28 記事 (1 - 20 表示)]  << 0 | 1 >>

■46937 / inTopicNo.1)  CSVファイル入出力時の速度向上方法について
  
□投稿者/ みち (1回)-(2010/02/14(Sun) 23:30:53)

分類:[VB6 以前] 

初めまして。
VB6について質問させていただきます。
開発環境:WinXP、MicroSoft Visual Basic 6.0

あるCSVファイル(Base)から、最初のヘッダ行を数行スキップし
以降の行(10万〜20万前後)を新しいCSVファイル(Tmp)に保存する処理を作っています。
(スキップする行数はCSVファイル毎に可変)

そこで以下のように作成したのですが、
もう少し処理速度を早く出来ないかと要望が降りてきてしまいどうしたらいいか悩んでいます。
どのようにしたらさらに処理速度を上げることができるでしょうか。

Sub CSVファイル作成(Byval スキップ行数 As Integer)

Dim BaseFso As New FileSystemObject
Dim TmpFso As New FileSystemObject
Dim BaseTs As TextStream
Dim TmpTs As TextStream
Dim i As Integer
Dim strSkipRow As string

'CSVファイルセット
Set BaseTs = BaseFso.OpenTextFile([BaseCSVファイルのパス])
Set TmpTs = TmpFso.CreateTextFile([TmpCSVファイルのパス])

'BaseCSVファイル行スキップ
for i = 1 To スキップ行数
BaseTs.SkipLine
next

'TmpCSVファイルへ、BaseCSVのデータ書き込み
Do Until(BaseTs.AtEndofLine)
 TmpTs.Write(BaseTs.ReadLine & vbNewLine)
Loop

End Sub
引用返信 編集キー/
■46943 / inTopicNo.2)  Re[1]: CSVファイル入出力時の速度向上方法について
□投稿者/ やじゅ (1531回)-(2010/02/15(Mon) 02:23:56)
やじゅ さんの Web サイト
No46937 (みち さん) に返信
> もう少し処理速度を早く出来ないかと要望が降りてきてしまいどうしたらいいか悩んでいます。
> どのようにしたらさらに処理速度を上げることができるでしょうか。

単純に考えたのは、1つのファイルを半分の行数ずつ読んで、前半と後半で2つのファイルに
書き込んで、最後にファイル連結をする。

テキストファイルの行数はForAppendingで取得出来るみたいだしね。
逆に遅くなる可能性もあるけど。

FileSystemObject オブジェクト関係
http://hanatyan.sakura.ne.jp/vbhlp/FSOflm.htm

コマンドプロンプトで2つのファイルを結合する
http://cmd-pro.com/m_com.html
引用返信 編集キー/
■46945 / inTopicNo.3)  Re[1]: CSVファイル入出力時の速度向上方法について
□投稿者/ .SHO (1209回)-(2010/02/15(Mon) 08:31:36)
No46937 (みち さん) に返信

スキップした後の内容は行単位で処理する必要はないですね。
引用返信 編集キー/
■46946 / inTopicNo.4)  Re[2]: CSVファイル入出力時の速度向上方法について
□投稿者/ れい (872回)-(2010/02/15(Mon) 08:32:56)
一般に、ファイルの先頭を削除するのはかなり難しい問題です。

とりあえず、
無視する行数を読んだ後に1行ずつ読んで書くのではなく、
1MByte程度ずつ読んで書くようにすると多少良くなると思います。

ですが、本質的には改善されないでしょう。

ドライブが複数用意できたり、莫大なRAID構成だったりする場合は違いますが、
ほぼすべての時間がディスクアクセス、とくに書き込みに取られるはずです。

ですので、解決するには少し工夫が必要になります。

No46943 (やじゅ さん) に返信
> 単純に考えたのは、1つのファイルを半分の行数ずつ読んで、前半と後半で2つのファイルに
> 書き込んで、最後にファイル連結をする。

書き込み速度がボトルネックになっているはずですので、
やじゅさんのやりかたでは余計に時間を食うはずです。

ファイルの大部分が実質変更されていないので、そこを書き直さないようにすればいいのですが、
殆どのファイルシステムでは、これは大変困難な作業になります。

ですが、CSVの特徴をうまく使えば比較的簡単にできます。

たとえば、最終的にCSVを読むソフトウェアに、
「コメント行を意味するエスケープ」がある場合があります。
行頭に「#」があったら移行は読まない、というような。

そういうものがあるのでしたら飛ばしたい行の先頭に「#」を書けば目的が達成されます。
「上書き」で書けば先頭の1セクタorクラスタ分の書き込みで済みます。

CSVに、余計な列を一つ付けてもいい、という条件でも構いません。
最初の1行の後ろに、次の行とうまく整合するように無駄なバイト列を追加するだけです。

CSVに、長さ可変の列、たとえば数字の列がある場合、「1」と「0001」が同じ値を意味する場合は、
これを利用する手もあります。

当然、無駄文字のあるUnicodeを使う手もあります。少し危険ですが。

バイト数と行数と、両方管理してうまく整合させるのでアルゴリズムは面倒ですが、
うまくつくれば何万倍も速く処理できます。
HDDへの負荷も小さいし。

引用返信 編集キー/
■46948 / inTopicNo.5)  Re[3]: CSVファイル入出力時の速度向上方法について
□投稿者/ .SHO (1210回)-(2010/02/15(Mon) 08:49:53)
No46946 (れい さん) に返信

> 無視する行数を読んだ後に1行ずつ読んで書くのではなく、
> 1MByte程度ずつ読んで書くようにすると多少良くなると思います。
>
> ですが、本質的には改善されないでしょう。

20万行のループでも改善されないですかね?
結構、変わると思うけど…試してないけど。
引用返信 編集キー/
■46949 / inTopicNo.6)  Re[2]: CSVファイル入出力時の速度向上方法について
□投稿者/ なちゃ (390回)-(2010/02/15(Mon) 09:06:21)
実際にどうなるかは試してみないと分かりませんが、
1行ずつと言ってもOSのキャッシュが間に入りますので、
あまり変わらない可能性はあります。
FSO自体にもバッファはある気がしますし。
とはいえ、変わる可能性はありますのでもちろん試す価値はあると思いますが。
引用返信 編集キー/
■46950 / inTopicNo.7)  Re[3]: CSVファイル入出力時の速度向上方法について
□投稿者/ なちゃ (391回)-(2010/02/15(Mon) 09:08:25)
あ、OSのキャッシュよりもFSO自体のバッファが大きいかな?

引用返信 編集キー/
■46952 / inTopicNo.8)  Re[4]: CSVファイル入出力時の速度向上方法について
□投稿者/ .SHO (1211回)-(2010/02/15(Mon) 09:24:44)
No46950 (なちゃ さん) に返信

キャッシュが効くのでファイルのI/Oは私もさほど変わらないと思います。
ようは20万回のループが効くと思うのですが…

しかも内部では、20万回の行末を探す処理が入る(ということは1バイトづつ
ファイルの中身を全部捜査するわけですよね)わけで、何も考えずに一気に
多くのバイトを移動した方が、はるかに速いと思うのですが。

って、試してみればいいんですけどね。。。^^;
引用返信 編集キー/
■46958 / inTopicNo.9)  Re[5]: CSVファイル入出力時の速度向上方法について
□投稿者/ やじゅ (1532回)-(2010/02/15(Mon) 10:33:59)
コマンドライン版のファイル分割ツールを使って、ファイル分割して
ファイル分割の先頭ファイルを加工するなりした後に、ファイル結合するとか
速度的にどうなるか分からないけど、試す価値はあるかな。

下記ツール以外にも探せばあるはず。
例 テキストファイル分割プログラム 1.02
http://www.vector.co.jp/soft/win95/util/se451260.html
引用返信 編集キー/
■46959 / inTopicNo.10)  Re[3]: CSVファイル入出力時の速度向上方法について
□投稿者/ みきぬ (782回)-(2010/02/15(Mon) 11:02:08)
No46946 (れい さん) に返信
> ファイルの大部分が実質変更されていないので、そこを書き直さないようにすればいいのですが、
> 殆どのファイルシステムでは、これは大変困難な作業になります。
>
> ですが、CSVの特徴をうまく使えば比較的簡単にできます。

(snip...)

> バイト数と行数と、両方管理してうまく整合させるのでアルゴリズムは面倒ですが、
> うまくつくれば何万倍も速く処理できます。
> HDDへの負荷も小さいし。

今回の話は、元のCSVファイルとは別の新しいCSVファイルに保存するのだから、
新しいCSVファイルのサイズ分の書き込みはどうやったって発生するんじゃない?

それとも、元のCSVファイルをまるっとコピーしてから編集するほうが速いよって話?
引用返信 編集キー/
■46961 / inTopicNo.11)  Re[6]: CSVファイル入出力時の速度向上方法について
□投稿者/ 774RR (463回)-(2010/02/15(Mon) 11:15:59)
うむ、何をどうあがいても
「元ファイルを読み出す時間+結果ファイルを書き出す時間」は削れない
(しかもこの時間はディスク装置律速なのでプログラムの書き方に無関係であるはず)
ので、元発言者様への提言としては:

1)ファイルを加工しないでただコピーするのに要する時間測定
2)ファイルを加工しながら出力するのに要する時間測定
1,2 で大差がないのであれば、ハードウェア制約上それ以上速くできないということ。
まずこれから確認だね

ソフトを直すのはその後。
引用返信 編集キー/
■47004 / inTopicNo.12)  Re[7]: CSVファイル入出力時の速度向上方法について
□投稿者/ こあら (74回)-(2010/02/16(Tue) 00:01:02)
VBScriptでADBDB.Streamを使って「一行ずつ」と「残り一括」を比較したら、雲泥の差でしたよ。


Option Explicit
'On Error Resume Next

Const adTypeText = 2
Const adCRLF = -1
Const adLF = 10
Const adCR = 13
Const adReadAll = -1
Const adReadLine = -2
Const adWriteLine = 1 

Const adSaveCreateNotExist = 1
Const adSaveCreateOverWrite = 2

dim i, istream, ostream, s

s = Now()

Set istream = WScript.CreateObject("ADODB.Stream")
Set ostream = WScript.CreateObject("ADODB.Stream")
With ostream
  .Type = adTypeText
  .Charset = "shift-jis"
  .LineSeparator = adCRLF
  .Open
End With

With istream
  .Type = adTypeText
  .Charset = "shift-jis"
  .LineSeparator = adCRLF
  .Open
  .LoadFromFile "C:\temp\input.csv"
  For i = 1 to 1000
    .SkipLine
  Next


' Do While not .EOS
'   ostream.WriteText .ReadText(adReadLine), adWriteLine
' Loop
'↑↓どちらかを有効にして速度を計ってください
' .CopyTo ostream
  .Close
End With

ostream.SaveToFile  "C:\temp\output.csv", adSaveCreateOverWrite
ostream.Close

Set istream = Nothing
Set ostream = Nothing

Msgbox FormatDateTime(Now() - s)

引用返信 編集キー/
■47005 / inTopicNo.13)  Re[7]: CSVファイル入出力時の速度向上方法について
□投稿者/ れい (874回)-(2010/02/16(Tue) 00:02:15)
No46959 (みきぬ さん) に返信
> ■No46946 (れい さん) に返信
>>ファイルの大部分が実質変更されていないので、そこを書き直さないようにすればいいのですが、
>>殆どのファイルシステムでは、これは大変困難な作業になります。
>>
>>ですが、CSVの特徴をうまく使えば比較的簡単にできます。
>
> それとも、元のCSVファイルをまるっとコピーしてから編集するほうが速いよって話?

No46961 (774RR さん) に返信
> うむ、何をどうあがいても
> 「元ファイルを読み出す時間+結果ファイルを書き出す時間」は削れない
> ソフトを直すのはその後。

あー。
意訳しすぎましたか。

私の言っているのは「元ファイルを残さなくてもいい」という条件付きでしたね。

元ファイルも、処理結果ファイルも、両方保持したいなら
コピーにかかる時間は必要ですね。

FAT32とかexFATなファイルシステムとか、
DAEMONToolsなどの仮想ファイルを使っていいならもっとエレガントに解決できるんですが。


引用返信 編集キー/
■47008 / inTopicNo.14)  Re[8]: CSVファイル入出力時の速度向上方法について
□投稿者/ みきぬ (787回)-(2010/02/16(Tue) 01:23:01)
No47004 (こあら さん) に返信
> VBScriptでADBDB.Streamを使って「一行ずつ」と「残り一括」を比較したら、雲泥の差でしたよ。
>
この結果から何が導かれるのか分からないので、補足を希望します。
引用返信 編集キー/
■47009 / inTopicNo.15)  Re[8]: CSVファイル入出力時の速度向上方法について
□投稿者/ れい (876回)-(2010/02/16(Tue) 01:52:17)
2010/02/16(Tue) 02:11:46 編集(投稿者)

No47004 (こあら さん) に返信
> VBScriptでADBDB.Streamを使って「一行ずつ」と「残り一括」を比較したら、雲泥の差でしたよ。

VB.Netでやってみました。

A.
1行1024Byte、200000行のUTF-8 csvファイル(200MByte)を作成

B.
ReadLineで最初の100行を削除
WriteLine(ReadLine)で残りを書き込み

C.
ReadLineで最初の100行を削除
1Mのバッファを用いてRead+Writeで残りを書き込み

D.
ReadLineで最初の100行を削除
次の100行の後ろにダミー文字列を追加して長さを調節して、残りは書かない。

という4つを測定しました。
結果、以下のようになりました。

A 1350 msec
B 2710 msec
C 1520 msec
D <10 msec

当然ながら、コピーを作らないのが圧倒的に早い。
エンコード+書き込みに1.35secに対して、
読み込み+デコード+エンコード+書き込みだとちょうど2倍の2.71sec。

HDDではなくSSDなので、そのまんまの速度になってますね。

一応スペックを。

CPU: Intel L9600 2.13G
Memory: 4GByte
Disk: TOSHIBA THNS128G

#.Netのベンチマークを公表するときの制限はまだあるのだろうか?


追記。

全部デバッグ環境で試しました。
リリースでも誤差1割以内です。

さらに、C.のケースで、書き込まない場合も計測してみると、720msecでした。
行末検査の速度は十分小さいものでした。
とすると

読み込み 700msec
書き込み 800msec
エンコード 500msec
デコード 700msec

くらいという計算になります。
ディスク書き込み速度だけが律速というわけではないんですね。

この結果からすると、エンコード/デコードと、書き込み/読み込みを非同期にすれば2倍ほど速くなるということになります。

およそ800msecでコピーができるはず。
実際、ファイルをコマンドプロンプトでコピーしたら1秒くらいでした。

うーん。

.Netが重いのかUTF-8が重いのか。
引用返信 編集キー/
■47010 / inTopicNo.16)  Re[9]: CSVファイル入出力時の速度向上方法について
□投稿者/ なちゃ (394回)-(2010/02/16(Tue) 08:29:47)
んー確かに重いと言えば重いですが、それでも秒間300MBとか400MBとかですよね?

まあSSDが速すぎる感じですが。
通常のHDDだとまた速度と特性が全然変わるはずですから、
そこまで差は出ないように思います。

複数ディスクやSSDでもパフォーマンスを最大限生かせるようにしようとすると、
このレベルでちゃんと意識する必要がありそうですね。

引用返信 編集キー/
■47018 / inTopicNo.17)  Re[10]: CSVファイル入出力時の速度向上方法について
□投稿者/ 中博俊 (1361回)-(2010/02/16(Tue) 11:33:08)
#.Netのベンチマークを公表するときの制限はまだあるのだろうか?

大丈夫ですー

http://www.microsoft.com/japan/academic/DreamSpark/eula.mspx

10条

MICROSOFT .NET FRAMEWORK のベンチマーク テスト。本ソフトウェアには、Windows オペレーティング システムの .NET Framework コンポーネント (以下「.NET コンポーネント」といいます) が含まれています。お客様は、.NET コンポーネントの内部ベンチマーク テストを実施することができます。お客様は、以下の条件に従うことを条件として、.NET コンポーネントのベンチマーク テストの結果を開示することができます。(1) お客様は、ベンチマーク テストの方法の完全かつ正確な詳細説明、テスト スクリプトないしテスト ケース、適用したパラメータ調整、テストしたハードウェアおよびソフトウェア プラットフォーム、テストに使用した第三者のテスト用ツールの名称およびバージョン、ならびにお客様によってもしくはお客様のために開発された .NET コンポーネントと競合製品の両方に使用されたテスト用ベンチマーク スイートないしベンチマーク ハーネスの完全なソースコードなど、ベンチマーク テストの追試に必要な情報をすべて開示しなければなりません。(2) お客様は、ベンチマーク テストの実施日、.NET コンポーネントを含むテスト対象マイクロソフト ソフトウェア製品のバージョン情報を開示しなければなりません。(3) お客様のベンチマーク テストは、製品付属の文書やマイクロソフトのサポート Web サイトに記載されたすべてのパフォーマンス調整およびベスト プラクティスのガイダンス、ならびに .NET コンポーネントおよび関連するマイクロソフトのオペレーティング システムについて利用可能な最新の更新プログラム、パッチ、修正プログラムを使用して実施されるものとします。(4) お客様は、上記に従う場合には、Web サイトのような公になっている場所にテスト結果を開示してよいものとします。ただし、お客様のベンチマーク テスト結果を開示するごとに、すべての必要な開示情報が含まれている公開されたサイトを明示的に特定することを条件とします。および、(5) 本条項は、お客様が保有するベンチマーク テストを実施するための他の権利を放棄させるものではありません。

引用返信 編集キー/
■47040 / inTopicNo.18)  Re[11]: CSVファイル入出力時の速度向上方法について
□投稿者/ れい (877回)-(2010/02/17(Wed) 00:00:24)
No47010 (なちゃ さん) に返信
> んー確かに重いと言えば重いですが、それでも秒間300MBとか400MBとかですよね?
>
> まあSSDが速すぎる感じですが。
> 通常のHDDだとまた速度と特性が全然変わるはずですから、
> そこまで差は出ないように思います。
>
> 複数ディスクやSSDでもパフォーマンスを最大限生かせるようにしようとすると、
> このレベルでちゃんと意識する必要がありそうですね。

その辺の古ーいサーバーでテストしてみた。
HDDで同じテストしてみた
(W2K3。Celeron 2.53GHz。4GByte。HDDはSeagateの160G)

A 3100 enc w
B 5900 rw enc dec
C 4400 rw
C' 4000 r

これだと何か違うことに時間を取られているようで。


No47018 (中博俊 さん) に返信
> #.Netのベンチマークを公表するときの制限はまだあるのだろうか?
>
> 大丈夫ですー
>

情報どうもです。
でも、DreamSpark使ってないし学生でもありません。

で、制限はあるのね…


> (1) お客様は、ベンチマーク テストの方法の完全かつ正確な詳細説明、
掲示板ログ=文脈から読めるはず。

> テスト スクリプトないしテスト ケース、
同上

> 適用したパラメータ調整、
掲示板ログによる。

> テストしたハードウェアおよびソフトウェア プラットフォーム、
OSはWin7
VS2005/2008両方。

> テストに使用した第三者のテスト用ツールの名称およびバージョン、
なし。

> ならびにお客様によってもしくはお客様のために開発された .NET コンポーネントと競合製品の両方に使用されたテスト用ベンチマーク スイートないしベンチマーク ハーネスの完全なソースコードなど、ベンチマーク テストの追試に必要な情報をすべて開示しなければなりません。

なし。

> (2) お客様は、ベンチマーク テストの実施日、.NET コンポーネントを含むテスト対象マイクロソフト ソフトウェア製品のバージョン情報を開示しなければなりません。

昨日。
.NetFramework2.0SP2

> (3) お客様のベンチマーク テストは、製品付属の文書やマイクロソフトのサポート Web サイトに記載されたすべてのパフォーマンス調整およびベスト プラクティスのガイダンス、ならびに .NET コンポーネントおよび関連するマイクロソフトのオペレーティング システムについて利用可能な最新の更新プログラム、パッチ、修正プログラムを使用して実施されるものとします。

した。つもり。

> (4) お客様は、上記に従う場合には、Web サイトのような公になっている場所にテスト結果を開示してよいものとします。ただし、お客様のベンチマーク テスト結果を開示するごとに、すべての必要な開示情報が含まれている公開されたサイトを明示的に特定することを条件とします。および、(5) 本条項は、お客様が保有するベンチマーク テストを実施するための他の権利を放棄させるものではありません。

ここで。
引用返信 編集キー/
■47041 / inTopicNo.19)  Re[9]: CSVファイル入出力時の速度向上方法について
□投稿者/ こあら (76回)-(2010/02/17(Wed) 00:43:13)
No47008 (みきぬ さん) に返信
> ■No47004 (こあら さん) に返信
>>VBScriptでADODB.Streamを使って「一行ずつ」と「残り一括」を比較したら、雲泥の差でしたよ。

> この結果から何が導かれるのか分からないので、補足を希望します。

「同じ出力ファイルを作るのに、手続きによって処理時間が異なる」です。

それまでの話の流れをコードで検証したつもりです。
ですが、聞かれたことに回答できていない気がするので、もう一度質問してください。

引用返信 編集キー/
■47047 / inTopicNo.20)  Re[10]: CSVファイル入出力時の速度向上方法について
 
□投稿者/ みきぬ (791回)-(2010/02/17(Wed) 10:04:44)
No47041 (こあら さん) に返信
> >>VBScriptでADODB.Streamを使って「一行ずつ」と「残り一括」を比較したら、雲泥の差でしたよ。
>
>>この結果から何が導かれるのか分からないので、補足を希望します。
>
> 「同じ出力ファイルを作るのに、手続きによって処理時間が異なる」です。
>
やり方によってはそういう場合もあるということはわかります。

ただ今回の話では、元質問者から具体的なコードが提示されています。
わざわざ別のやり方で結果を示す理由がわからなかったのです。
# VB6 の確認環境がないから、とかならわかるんだけど

さらに言うと、私から見たこあらさんのやりかたは、元質問者の方法を「わざわざ遅くしている」ようにも見えました。
こあらさんのやり方で雲泥の差が出ても、それが元質問者の方法でもそのような結果になるかというと、関係がないと思うのです。
# ADODB.Stream を知らない(CSV ファイルを DB のように扱ってるのかなあ、くらいの理解)し、
# 確認できる環境も持ってないので、このへんは単なる勘ですが
引用返信 編集キー/

次の20件>
トピック内ページ移動 / << 0 | 1 >>

管理者用

- Child Tree -