2

私は通常、 csvパーサーで説明されている方法を使用してスプレッドシートファイルを読み取ります。ただし、約40列と25万行のデータを含む64MBのファイルを読み取る場合、約4分かかります。元のメソッドでは、CSVRowクラスを使用してファイルを行ごとに読み取り、プライベートベクトルを使用してすべてのデータを行に格納します。

注意すべきいくつかの事柄:

  • 私はベクトルの十分な容量を予約しましたが、あまり役に立ちませんでした。
  • また、各行を読み取るときにクラスのインスタンスを作成する必要がありますが、コードがインスタンスを作成せずにデータを読み込んだだけでも、時間がかかります。
  • ファイルはコンマ区切りではなくタブ区切りですが、重要ではないと思います。

そのファイルの一部の列は有用なデータではないため、すべてのデータを格納するプライベート文字列メンバーを持つようにメソッドを変更し、(n-1)番目とn番目の区切り文字の位置を見つけて(のもちろん、多くの有用な列があります)。そうすることで、いくつかのpush_back操作を回避し、時間を2分強に短縮します。しかし、それでも私には長すぎるようです。

これが私の質問です:

  1. そのようなスプレッドシートファイルをより効率的に読み取る方法はありますか?

  2. 行ごとではなく、バッファごとにファイルを読み取ろうか?もしそうなら、どのようにバッファで読み取り、csvrowクラスを使用しますか?

  3. ブーストトークナイザーを試したことがありませんが、より効率的ですか?

ご協力ありがとうございました!

4

3 に答える 3

2

IO がボトルネックになっているようです。ファイルを 1 行ずつ読み取るのではなく、おそらく 8 MB のブロック単位で読み取ります。読み取ったブロックのレコードを解析し、ブロックの最後が部分的なレコードかどうかを判断します。そうである場合は、最後のレコードの一部をブロックからコピーし、次のブロックの先頭に追加します。ファイルがすべて読み込まれるまで繰り返します。このように、64 MB のファイルの場合、8 つの IO 要求しか作成しません。ブロック サイズを試して、何が最適なパフォーマンスとメモリ使用量を提供するかを判断できます。

于 2010-06-24T15:08:55.443 に答える
0

この記事は役に立つはずです。

要するに:
1. メモリ マップド ファイルを使用するか、4k バイト ブロックでファイルを読み取り、データにアクセスします。メモリ マップト ファイルは高速になります。
2. 解析ループ内で、push_back、std::string 操作 (+ など)、および stl からの同様のルーチンを使用しないようにしてください。それらは素晴らしいですが、すべて動的に割り当てられたメモリを使用し、動的メモリ割り当ては遅いです。頻繁に動的に割り当てられるものはすべて、プログラムを遅くします。解析する前に、すべてのバッファを事前に割り当ててみてください。メモリを事前に割り当てるためにすべてのトークンを数えることは難しくありません。
3. プロファイラーを使用して、速度低下の原因を特定します。
4. iostream の << および >> 演算子の使用を避け、ファイルを自分で解析することをお勧めします。

一般に、効率的な C/C++ パーサーの実装では、20 メガバイトの大きなテキスト ファイルを 3 秒以内に解析できるはずです。

于 2010-06-24T16:41:57.840 に答える
0

データ全体をメモリに読み込むことが許容される場合 (そして明らかにそうである場合)、次のようにします。

  1. ファイル全体を std::vector に読み込みます
  2. すべての改行文字とセルのデータの開始位置を含むベクトル > を設定します。これらの位置は、各セルの開始/終了を示します

アイデアを示すコード スケッチ:

vector<vector<vector<char>::size_Type> > rows;
for ( vector<char>::size_type i = 0; i < data.size(); ++i ) {
    vector<vector<char>::size_type> currentRow;
    currentRow.push_back( i );
    while ( data[i] != '\n' ) {
        if ( data[i] == ',' ) { // XXX consider comma at end of line
            currentRow.push_back( i );
        }
    }
    rows.push_back( currentRow );  
}
// XXX consider files which don't end in a newline

したがって、すべての改行とすべてのカンマの位置がわかり、完全な CSV 日付が 1 つの連続したメモリ ブロックとして利用可能になります。したがって、次のようにセル テキストを簡単に抽出できます。

// XXX error checking omitted for simplicity
string getCellText( int row, int col )
{
     // XXX Needs handling for last cell of a line
     const vector<char>::size_type start = rows[row][col];
     const vector<char>::size_type end = rows[row][col + 1]; 
     return string(data[start], data[end]);
}
于 2010-06-24T16:15:28.250 に答える