2

そのため、それぞれが特定のグループに属する数百万のレコードで構成される比較的大きなファイル(> = 1GB)を読み取っています。100のグループがあります。データをより効果的に処理するために、グループごとに1つずつ、100個のファイルを作成します。(追加モードでfopenを使用します。)大きなファイルからレコードを読み込むときに、それぞれを対応する小さなファイルに書き込みます。すべてのファイルのファイルポインタを開いたままにして、すべてのレコードでファイルを開いたり閉じたりしないようにします。

これには非常に長い時間がかかり、読み込み(および書き込み)の速度は一定ではありません。それは速く始まり、次にクロールまで遅くなり、次に再び速くなり、そして遅くなります。読み込まれるファイルが増えるほど悪化するようです。

何が起こっているかについての1つの可能性は、ファイルが大きくなるにつれて、小さいファイルをストレージに再配置する必要があるということです。私は47GB(〜500)の空きがあるので、これは驚くべきことです。しかし、私は他に何も考えられません。断片化が役立つかどうかはわかりますが、それまでの間、何が起こっているのか、これを修正する方法を誰かが知っていますか?作成するファイルのサイズを事前に指定する方法はありますstd::vector::reserveか?

4

4 に答える 4

2

ファイルシステムのキャッシュが容量までいっぱいになり、実際にディスクに書き込まれるデータによってスペースが解放されるまで待たなければならないという副作用が見られます。これは氷河的に遅いです。キャッシュにスペースがある間、write()呼び出しはメモリからメモリへのコピーを実行し、5ギガバイト/秒以上で実行されます。ディスクの書き込み速度が30メガバイト/秒を超えることはめったにありません。大きな違いがあり、キャッシュがいっぱいになったときのディスク書き込み速度を測定しています。

より多くのRAMまたはより高速なディスクが必要になります。

于 2012-12-14T11:28:16.007 に答える
2

一度に1つのグループを書き込むようにプログラムを再構築できない、または再構築したくない場合は、「小さな」ファイルごとに大きなバッファーを設定します(、setbufを使用setvbuf)。これの効果は、ディスクへのバッファフラッシュがより多くの「局所性」を示すことです。つまり、X量のデータを100回100の異なるファイルにフラッシュする代わりに、10X量のデータを10回100の異なるファイルにフラッシュします。

テストケースプログラム(意図的にエラーチェックなし):

-- hugefile.h --

struct record
{
  unsigned int group;
  char data [1020];
};


--- gen-hugefile.c ---

#include <stdio.h>
#include <stdlib.h>

#include "hugefile.h"

int
main (int argc, char **argv)
{
  unsigned int i, nrecords = strtol (argv [1], 0, 10);
  FILE *f;

  f = fopen ("hugefile.db", "w");

  for (i = 0; i < nrecords; ++i)
    {
      struct record r;
      r.group = rand () % 100;

      fwrite (&r, sizeof r, 1, f);
    }

  fclose (f);
  return 0;
}

--- read-hugefile.c ---

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>

#include "hugefile.h"

FILE *in;
FILE *out[100];

int
main ()
{
  int i;
  char name [128];
  in = fopen ("hugefile.db", "r");

#ifdef BUFFER
  setvbuf (in, malloc (2*BUFFER), _IOFBF, 2*BUFFER);
#endif

  for (i = 0; i < 100; ++i)
    {
      sprintf (name, "out/file%03d.db", i);
      out [i] = fopen (name, "w");
#ifdef BUFFER
      setvbuf (out [i], malloc (BUFFER), _IOFBF, BUFFER);
#endif
    }

  struct record r;
  while ((i = fread (&r, sizeof r, 1, in)) == 1)
    fwrite (&r, sizeof r, 1, out [r.group]);

  fflush (0);
  return 0;
}

velco@sue:~/tmp/hugefile$ ls
gen-hugefile.c  hugefile.h  read-hugefile.c
velco@sue:~/tmp/hugefile$ gcc -O2 gen-hugefile.c -o gen-hugefile
velco@sue:~/tmp/hugefile$ ./gen-hugefile 1000000
velco@sue:~/tmp/hugefile$ ls -lh
total 978M
-rwxrwxr-x 1 velco velco 8.5K Dec 14 13:33 gen-hugefile
-rw-rw-r-- 1 velco velco  364 Dec 14 13:31 gen-hugefile.c
-rw-rw-r-- 1 velco velco 977M Dec 14 13:34 hugefile.db
-rw-rw-r-- 1 velco velco   61 Dec 14 12:56 hugefile.h
-rw-rw-r-- 1 velco velco  603 Dec 14 13:32 read-hugefile.c
velco@sue:~/tmp/hugefile$ gcc -O2 read-hugefile.c -o read-hugefile
velco@sue:~/tmp/hugefile$ gcc -O2 -DBUFFER=1048576 read-hugefile.c -o read-hugefile-buf
velco@sue:~/tmp/hugefile$ mkdir out
velco@sue:~/tmp/hugefile$ time ./read-hugefile

real    0m34.031s
user    0m0.716s
sys 0m6.204s
velco@sue:~/tmp/hugefile$ time ./read-hugefile

real    0m25.960s
user    0m0.600s
sys 0m6.320s
velco@sue:~/tmp/hugefile$ time ./read-hugefile-buf

real    0m20.756s
user    0m1.528s
sys 0m5.420s
velco@sue:~/tmp/hugefile$ time ./read-hugefile-buf

real    0m16.450s
user    0m1.324s
sys 0m5.012s
velco@sue:~/tmp/hugefile$ 
于 2012-12-14T10:53:42.813 に答える
1

プロセスに100個のファイルを開くだけ、または1つのディレクトリに100個のファイルを開くことは、最近のシステムのボトルネックにはなりません。ただし、101個のファイルと合計2GBのデータへの同時ランダムアクセスが可能です。

私はこれを行います:

大きなファイルからある程度のレコードを読み取り、各タイプのレコードをメモリ内の独自のリストに保存します。約10メガバイト相当のレコードを読み取ることはおそらく十分な量であり、まともなパフォーマンスが得られますが、これは使用可能なRAMによって異なります(OSがこのためにスワップファイルを使用し始めるほど多くは使用したくない...)。

次に、メモリ内の100個のレコードリストを一度に1つずつ調べ、一度に1つのファイルに追加します。すべてのファイルを開いたままにしておくことができますが、これはおそらく問題にはなりませんが、必要に応じてファイルを閉じて開くこともできます。このように一度に1つのファイルを処理する場合、オーバーヘッドはそれほど大きくありません。

于 2012-12-14T11:42:08.577 に答える
0

それらをメモリ内で並べ替えて、一度に1つのグループに書き出すことができるように思えます。

于 2012-12-14T10:27:18.350 に答える