2017-08-07 10 views
0

私はCSVリーダーを使用して、データの解析に多くの時間がかかることがわかりました。 csvファイル全体をメモリにロードして、レコードのカスタムマッピングを行う必要があるので、レコードごとにレコードを処理するにはどうすればいいですか?ファイルを完全にロードしてレコードcsvreaderを処理する方法は?

TextReader tr = new StreamReader(File.Open(@"C:\MarketData\" + symbol + ".txt", FileMode.Open)); 
    CsvReader csvr = new CsvReader(tr); 
    while (csvr.Read()) 
{ 
// do your magic 
} 
+0

.NETストリームでは既にバッファリングが使用されていますので、問題は確実ですか?ファイルのサイズはどれくらいですか?** async **メソッド – MickyD

+0

をファイルごとに約10 MB試してみてください – junkone

答えて

0

直接質問に答えるには:ファイルをメモリストリームに完全にロードしてから、CsvReaderを使用してそのストリームから再度読み込むことができます。同様に、ファイルストリーム用のより大きな読み込みバッファ、たとえば15MBを作成して、ファイル全体を1回の読み込みでバッファに読み込むこともできます。私は、これらのいずれかが実際に10MBのファイルのパフォーマンスを向上させるかどうかは疑問です。

実際のパフォーマンスのボトルネックを見つけます:ディスクからファイルコンテンツを読み込む時間、CSVをフィールドに解析する時間、またはレコードを処理する時間? 10MBのファイルは本当に小さく見えます。私は250MB + csvファイルのセットをカスタムcsvリーダーで処理していますが、苦情はありません。

処理がボトルネックであり、複数のスレッドが使用可能で、csvファイル形式でエスケープされた改行をサポートする必要がない場合は、ファイル全体を行のリスト(System.IO.File.ReadAllLines/.ReadLines)、異なる行を使用して各行を解析します。例:

System.IO.File.ReadLines() 
.Skip(1)     // header line. Assume trusted to be correct. 
.AsParallel() 
.Select(ParseRecord)  // RecordClass ParseRecord(string line) 
.ForAll(ProcessRecord); // void ProcessRecord(RecordClass) 

多くのファイルを解析する場合は、各ファイルを別のタスクで処理し、非同期メソッドを使用してスループットを最大化できます。それらがすべて同じ物理ディスクから来た場合、あなたのマイルは変化し、シングルスレッドのアプローチよりも悪化することさえあります。

より高度な:あなたが唯一の8ビット文字が含まれているためにあなたのファイルを知っている場合

、あなたはバイト配列を操作し、文字にバイトをキャストするのStreamReaderのオーバーヘッドをスキップすることができます。こうすることで、ファイル全体を1回の呼び出しでバイト配列に読み込み、改行エスケープをサポートする必要がないと仮定して改行をスキャンすることができます。その場合、改行のスキャンは複数のスレッドで行うことができ、それぞれがバイト配列の一部を参照します。

フィールドエスケープ(a、 "b、c"、d)をサポートする必要がない場合、フィールド区切り文字(通常カンマ)を探すだけで高速パーサーを作成できます。ボトルネックの場合は、フィールド境界解析とフィールドコンテンツ解析をスレッドに分割することもできますが、メモリアクセスの局所性によって利益が損なわれる可能性があります。

特定の状況では、フィールドを中間データ構造(例えば、倍精度や文字列)に解析する必要はなく、フィールドの開始/終了の参照を直接処理して中間データ構造の作成を省くことができます。

4

CSVファイルを正確に表す/ミラーリングするクラスを作成します。その後、すべての内容をそのクラスのリストに読み込みます。次のスナップは、CsvHelperのドキュメントにあります。これはむしろ、あなたがそれらにアクセスするような結果をもたらすよりも、あなたのリストにすべてのデータのロードを強制するよう

var csv = new CsvReader(textReader); 
var records = csv.GetRecords<MyClass>().ToList(); 

重要な部分は、.ToList()です。

これで、そのリストの追加のマッピング/抽出を実行して、メモリに保存することができます。

既にこれを行っている場合は、List To(ToHashSet())ではなく、あなたのcsvをHashSetにロードすると便利です。 HashSet vs List Performance

関連する問題