13

私は非常に単純なことをしています: テキストファイル全体をディスクからstd::string. 私の現在のコードは基本的にこれを行います:

std::ifstream f(filename);
return std::string(std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>());

これがプログラムのパフォーマンスに何らかの影響を与える可能性はほとんどありませんが、これが遅い方法であるかどうかはまだ知りませんでした.

文字列の構築に多くの再割り当てが必要になるリスクはありますか? seekg()/を使用して、読み取りを行う前にtellg()ファイルのサイズと文字列内のそのスペースを計算する方が良い (つまり、より速い)でしょうか?reserve()

4

3 に答える 3

37

あなたの実装(1)、私の(2)、およびstackoverflowで見つけた他の2つ(3と4)のベンチマークを行いました。

結果 (100 回の実行の平均。gettimeofday を使用して計時、ファイルは lorem ipsum の 40 段落でした):

  • readFile1: 764
  • readFile2: 104
  • readFile3: 129
  • readFile4: 402

実装:

string readFile1(const string &fileName)
{
    ifstream f(fileName.c_str());
    return string(std::istreambuf_iterator<char>(f),
            std::istreambuf_iterator<char>());
}

string readFile2(const string &fileName)
{
    ifstream ifs(fileName.c_str(), ios::in | ios::binary | ios::ate);

    ifstream::pos_type fileSize = ifs.tellg();
    ifs.seekg(0, ios::beg);

    vector<char> bytes(fileSize);
    ifs.read(&bytes[0], fileSize);

    return string(&bytes[0], fileSize);
}

string readFile3(const string &fileName)
{
    string data;
    ifstream in(fileName.c_str());
    getline(in, data, string::traits_type::to_char_type(
                      string::traits_type::eof()));
    return data;
}

string readFile4(const std::string& filename)
{
    ifstream file(filename.c_str(), ios::in | ios::binary | ios::ate);

    string data;
    data.reserve(file.tellg());
    file.seekg(0, ios::beg);
    data.append(istreambuf_iterator<char>(file.rdbuf()),
                istreambuf_iterator<char>());
    return data;
}
于 2009-02-08T00:22:04.663 に答える
2

それをやってみたら演奏はどうなるの?「どの方法が速いですか?」と尋ねる代わりに。あなたは「ねえ、これを測定できる」と思うことができます。

特定のサイズのファイルを 10000 回程度読み取るループを設定し、時間を計ります。次に、そのreserve()方法と時間でそれを行います。いくつかの異なるファイル サイズ (小さいものから巨大なものまで) で試してみて、何が得られるかを確認してください。

于 2009-02-07T21:15:56.240 に答える
0

正直なところ、確かではありませんが、私が読んだことから、それは本当にイテレータに依存しています。ファイル ストリームからのイテレータの場合、開始インタレータと終了インタレータの間のファイルの長さを測定するメソッドが組み込まれていない可能性があります。

これが正しければ、スペースがなくなるたびに内部ストレージのサイズを 2 倍にするのと同じように動作します。この場合、ファイル内の n 文字に対して、文字を文字列にコピーするだけでなく、Log[n,2] のメモリ割り当てとメモリの削除、および n*Log[n,2] の個々の文字のコピーが行われます。

ただし、Greg が指摘したように、テストすることもできます。彼が言ったように、両方の手法でさまざまなファイル サイズを試してみてください。さらに、以下を使用して定量的なタイミングを取得できます。

#include<time.h>
#include<iostream>

...

clock_t time1=0, time2=0, delta;
float seconds;

time1=clock();

//Put code to be timed here

time2=clock();

delta= time2-time1;

seconds =(((float)delta)/((float)CLOCKS_PER_SEC));

std::cout<<"The operation took: "<<seconds<<" seconds."<<std::endl;

...

これは、タイミングのトリックを行う必要があります。

于 2009-02-07T21:29:53.310 に答える