-4

40MB の CSV ファイルを解析しています。

今のところ問題なく動作し、解析もかなり簡単です。私が抱えている唯一の問題はパフォーマンスです。もちろんかなり遅いです。

これを改善できる方法があるかどうか知りたいのですが、見つけたキーで検索してループを停止するだけでよいため、エントリがファイルの先頭にある場合はすぐに終了しますが、しばらく時間がかかります。

ランダムな開始行を与えることでこれをバランスさせることができますが、アルゴリズムは依然として O(n) になります...だから、それが本当に価値があるかどうかはわかりません.

順次解析アルゴリズムを改善する方法はありますか?

4

6 に答える 6

4

まず、「巨大な CSV ファイルを読み込んでいます」と「40MB の CSV ファイルを解析しています。」ここには 10 ギガバイト以上のスペース区切りのファイルがあります。これらを何と呼びますか?

また、ファイルのサイズは関係ありません。通常は行ごとに処理します。

私が抱えている唯一の問題はパフォーマンスです。もちろんかなり遅いです

定義。何が遅いと思いますか?それらの解析は、適切に行われると非常に高速です。

これを改善できる方法があるかどうか知りたいのですが、見つけたキーで検索してループを停止するだけでよいため、エントリがファイルの先頭にある場合はすぐに終了しますが、しばらく時間がかかります。

CSV ファイルを使用しないでください。60 年以上前に、人々はこのためのデータベースを発明しました。

逐次解析アルゴリズムを改善する方法はありますか?

あなたは、解析を別のスレッドに引き込み、効率的なコードを使用することを除いて意味します(あなたが持っていないかもしれません-誰も知りません)。

理論的には、次のことができます。

  • 適切なバッファーを使用して、1 つのスレッドで読み取ります (IO が少ない = 高速)

  • フィールド分割をスレッド 2 に移動 (オプション)

  • タスクを使用してフィールドを解析します (フィールドごとに 1 行に 1 つ) ので、すべてのプロセッサを使用できます)。

私は現在、いくつかの (約 10.000) ファイル (悲しいことに 2 桁のギガバイトのサイズ) を処理しています... 私はこの方法 (特定の順序で処理する必要があります) でコンピューターを完全に使用します。

それはあなたに多くを与えるはずです-そして真剣に、40MBのファイルは0.x秒(0.5 - 0.6)でロードするはずです.

それでも、それは非常に非効率的です。すべての人のようにファイルをデータベースにロードしない理由はありますか? CSV は、一部のトランスポート形式としては優れていますが、データベースとしては最悪です。

于 2012-05-30T15:44:17.713 に答える
3

csv を通常のデータベースに変換してみませんか。sqlexpress でも問題ありません。

于 2012-05-30T15:39:32.130 に答える
3

もちろん。

アルファベット順に並べるとします。
次に、真ん中から始めます。
反復ごとに、上部または下部の中央に移動します。適切なキーを持つ方。

このアルゴリズムには O(log n ) があります。

これは「二分探索」と呼ばれ、「Mike Christianson」が彼のコメントで示唆していることです。

于 2012-05-30T15:40:27.507 に答える
1

1 つの 40Mb ファイルをより小さなサイズのいくつかのファイルに分割することをお勧めします。Parallel.ForEachを使用すると 、ファイル処理のパフォーマンスを向上させることができます

于 2012-05-30T15:43:16.123 に答える
0

CSVをDataTableにロードして、ループするよりも高速な利用可能な操作を使用できます

それをデータベースにロードし、それに対して操作を実行することは別のオプションです

于 2012-05-30T15:50:55.697 に答える
0

これは、CSVファイルを順番に読み取るための最速の方法だと思います。CSVからデータを抽出する方法は他にもあるかもしれませんが、このアプローチに限定した場合は、このソリューションが役立つ可能性があります。

const int BUFFER_SIZE = 0x8000;  //represents 32768 bytes
public unsafe void parseCSV(string filePath)
{
     byte[] buffer = new byte[BUFFER_SIZE];
     int workingSize = 0; //store how many bytes left in buffer
     int bufferSize = 0; //how many bytes were read by the file stream
     StringBuilder builder = new StringBuilder();
     char cByte; //character representation of byte
     using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
     {
         do
         {
              bufferSize = fs.Read(buffer, 0, BUFFER_SIZE);
              workingSize = bufferSize;
              fixed (byte* bufferPtr = buffer)
              {
                   byte* workingBufferPtr = bufferptr;
                   while (workingSize-- > 0)
                   {
                        switch (cByte = (char)*workingBufferPtr++)
                        {
                            case '\n':
                                break;
                            case '\r':
                            case ',':
                                builder.ToString();
                                builder.Clear();
                                break;
                            default:
                                builder.Append(cByte);
                                break;
                        }
                   }
              }
         } while (bufferSize != 0);
     }
}

説明:

  • ファイルをバイトバッファに読み込みます。Filestreamこれは、常に高速なアクセスを提供する基本クラスを使用して行われます。Read()
  • 安全でないコード。通常、安全でないコードは使用しないことをお勧めしますが、あらゆる種類のバッファーをトラバースする場合は、ポインターを使用すると速度が向上する可能性があります。
  • StringBuilderキーを再テストするために、バイトを実行可能な文字列に連結するためです。StringBuilderは、バイトを一緒に追加し、実行可能な文字列を取得するための最速の方法です。

この方法はRFC4180にかなり不満があることに注意してください。ただし、引用符を扱う場合は、トリミングを処理するために投稿したコードを簡単に変更できます。

于 2012-05-30T16:13:07.147 に答える