34

以下は、ファイルに 50,000,000 バイトを書き込む 2 つのプログラムです。

C で記述された最初のプログラムは、バッファを使用します。このバッファは、任意の値が書き込まれると、ディスクに書き込み、50,000,000 バイトすべてが書き込まれるまでそのプロセスを繰り返します。バッファのサイズを大きくすると、プログラムの実行時間が短くなることに気付きました。たとえば、BUFFER_SIZE = 1 では、プログラムは ~88.0463 秒かかりましたが、BUFFER_SIZE = 1024 では、プログラムは ~1.7773 秒しかかかりませんでした。私が記録した最高の時間は、BUFFER_SIZE = 131072 のときでした。BUFFER_SIZE がそれよりも大きくなるにつれて、実際には少し時間がかかり始めていることに気付きました。

C++ で記述された 2 番目のプログラムは、ofstream を使用して一度に 1 バイトずつ書き込みます。驚いたことに、プログラムの実行にはわずか 1.87 秒しかかかりませんでした。BUFFER_SIZE = 1 の C プログラムのように、1 分ほどかかると予想していました。私のデータによると、BUFFER_SIZE = 512 の C ファイルとほぼ同じように実行されています。バックグラウンドで何らかのバッファを使用していますか?

Cプログラムは次のとおりです。

const int NVALUES = 50000000; //#values written to the file
const char FILENAME[] = "/tmp/myfile";
const int BUFFER_SIZE = 8192; //# bytes to fill in buffer before writing

main()
{
    int fd;  //File descriptor associated with output file
    int i;
    char writeval = '\0';
    char buffer[BUFFER_SIZE];

    //Open file for writing and associate it with the file descriptor
    //Create file if it does not exist; if it does exist truncate its size to 0
    fd = open(FILENAME, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR);

    for(i=0;i<NVALUES;i++)
    {
        //Package bytes into BUFFER_SIZE chunks 
                //and write a chunk once it is filled
        buffer[i%BUFFER_SIZE] = writeval;
        if((i%BUFFER_SIZE == BUFFER_SIZE-1 || i == NVALUES-1))
            write(fd, buffer, i%BUFFER_SIZE+1);

    }

    fsync(fd);

    close(fd);
}

C++ プログラムは次のとおりです。

int main()
{
    ofstream ofs("/tmp/iofile2");
    int i;

    for(i=0; i<50000000; i++)
        ofs << '\0';

    ofs.flush();
    ofs.close();

    return 0;
}

お時間をいただきありがとうございます。

4

3 に答える 3

14

はい、すべてのストリーム操作はバッファリングされますが、デフォルトでは標準の入力、出力、およびエラー出力はバッファリングされないため、CIOとの相互作用はそれほど驚くべきものではありません。

すでに触れたようstreambufに、舞台裏で使用される基本クラスがあります。独自のバッファが用意されており、そのサイズは実装の詳細です。

streambuf::in_avail入力ファイルストリームと出力ファイルストリームが同じバッファサイズで設定されていると仮定すると、を使用してこのバッファの量を(実験的に)確認できます。

ここで実行できる操作は他に2つあり、興味深いものになる可能性があります。

  • streambufストリームで使用されるオブジェクトを変更して、カスタムバージョンに切り替えることができます
  • streambufオブジェクトが使用するバッファを変更できます

flush一部のデータが失われないように、両方ともストリームの作成直後または後のいずれかで実行する必要があります。

バッファの変更を説明するために、以下をチェックしてくださいstreambuf::putsetbuf

#include <fstream>
#include <vector>

int main () {
  std::vector<char> vec(512);

  std::fstream fs;
  fs.rdbuf()->pubsetbuf(&vec.front(), vec.size());

  // operations with file stream here.
  fs << "Hello, World!\n";

  // the stream is automatically closed when the scope ends, so fs.close() is optional
  // the stream is automatically flushed when it is closed, so fs.flush() is optional

  return 0;
}

これで、Cで行った実験を繰り返して、スイートスポットを見つけることができます:)

于 2012-05-04T15:12:14.573 に答える
13

はい、ostream は、テンプレート basic_streambuf のインスタンス化の一部のサブクラスであるストリーム バッファーを使用します。basic_streambuf のインターフェースは、利点があれば実装でバッファリングできるように設計されています。

ただし、これは実装の品質の問題です。実装はこれを行う必要はありませんが、有能な実装であれば必要です。

ISO 標準の第 27 章ですべてを読むことができますが、より読みやすいソースはThe C++ Standard Library: A Tutorial and Reference ( google search ) です。

于 2012-05-04T13:33:49.337 に答える
3

thisごとにofstream、内部ポインターがあり、オブジェクトを指す関数をfilebuf介して読み取ることができます。これは次のとおりです。rdbufstreambuf

streambufオブジェクトは通常、1 つの特定の文字シーケンスに関連付けられており、そこから内部メモリ バッファを介してデータを読み書きします。バッファはメモリ内の配列であり、必要に応じて関連する文字シーケンスの物理コンテンツと同期されることが期待されます。

重要な部分を太字にしました。これはバッファを使用しているようですが、それがどのような種類のバッファなのかわかりません。

于 2012-05-04T13:30:33.843 に答える