10

最近、私が行っていたファイルの読み取りを最適化することにしました。なぜなら、誰もが言うように、大量の小さな読み取りを使用するよりも、大量のデータをバッファーに読み取ってから操作する方が速いからです。そして、私のコードは確かに今でははるかに高速ですが、いくつかのプロファイリングを行った後、memcpy に多くの時間がかかっているようです。

私のコードの要点は...

ifstream file("some huge file");
char buffer[0x1000000];
for (yada yada) {
    int size = some arbitrary size usually around a megabyte;
    file.read(buffer, size);
    //Do stuff with buffer
}

私はVisual Studio 11を使用していますが、コードをプロファイリングした後、内部バッファからバッファにコピーするifstream::read()呼び出しが最終的に表示されます。xsgetn()この操作は時間の 80% 以上を占めます。2 位はuflow()10% の時間を占めています。

このコピーを回避する方法はありますか? ifstream必要なサイズをバッファに直接バッファするようにどうにかして伝えることはできますか? C スタイルFILE*もそのような内部バッファを使用しますか?

更新: cstdio を使用するように言われたので、ベンチマークを行いました。

編集: 残念ながら、古いコードは失敗に満ちていました (ファイル全体を読み取ることすらできませんでした!)。ここで見ることができます:http: //pastebin.com/4dGEQ6S7

これが私の新しいベンチマークです。

const int MAX = 0x10000;
char buf[MAX];
string fpath = "largefile";
int main() {
    {
        clock_t start = clock();
        ifstream file(fpath, ios::binary);
        while (!file.eof()) {
            file.read(buf, MAX);
        }
        clock_t end = clock();
        cout << end-start << endl;
    }
    {
        clock_t start = clock();
        FILE* file = fopen(fpath.c_str(), "rb");
        setvbuf(file, NULL, _IOFBF, 1024);
        while (!feof(file)) {
            fread(buf, 0x1, MAX, file);
        }
        fclose(file);
        clock_t end = clock();
        cout << end-start << endl;
    }
    {
        clock_t start = clock();
        HANDLE file = CreateFile(fpath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, NULL, NULL);
        while (true) {
            DWORD used;
            ReadFile(file, buf, MAX, &used, NULL);
            if (used < MAX) break;
        }
        CloseHandle(file);
        clock_t end = clock();
        cout << end-start << endl;
    }
    system("PAUSE");
}

時間:
185
80
78

ええと... C スタイルの fread を使用すると、ifstream::read よりも高速に見えます。同様に、Windows ReadFile を使用しても無視できるわずかな利点しかありません (私はコードを見て、基本的に fread は ReadFile のラッパーです)。結局フレッドに乗り換えそうです。

このことを実際に正しくテストするベンチマークを書くのは混乱します。

結論: を使用した<cstdio>方が より高速です<fstream>。fstream が遅い理由は、c++ ストリームに独自の内部バッファーがあるためです。これにより、読み取り/書き込みのたびに余分なコピーが発生し、このコピーが fstream にかかる余分な時間全体を占めます。さらに衝撃的なのは、実際にファイルを読み取るのにかかる時間よりも余分にかかる時間が長いということです。

4

3 に答える 3

5

どういうわけか、必要なサイズをバッファに直接バッファリングするようにifstreamに指示できますか?

はい、これがpubsetbuf()の目的です。

ただし、ファイルの読み取り中にコピーすることに関心がある場合は、メモリマッピングも検討してください。ブーストには、移植可能な実装があります。

于 2012-04-25T22:19:28.680 に答える
2

ファイルI/Oを高速化したい場合<cstdio>は、C ++よりも大幅にパフォーマンスが優れているため、古き良きものを使用することをお勧めします。

于 2012-04-25T22:19:45.403 に答える
1

mmap()データを読み取る最速の方法はLinux システムであることが何度か証明されています。Windowsについてはわかりません。ただし、このバッファリングがなくても確実に機能します。

fopen(), fread(), fwrite()( FILE*) はやや高レベルであり、バッファーを誘発する 可能性がありますがopen()、 , read(),write()関数は低レベルであり、そこにある可能性がある唯一のバッファーは Os カーネルからのものです。

于 2012-04-25T22:21:27.047 に答える