2

コードの最初の部分:

// code is a private "global variable" for the class
// SourceCodeBuilder is a class that uses StringBuilder()
// basically it is based on String(s), formatted and with many appends depending on the "loc()" calls (see below)
private SourceCodeBuilder code = new SourceCodeBuilder();

[...]

    // create "file.txt" and call algorithm
    fileOut = new FileWriter("file.txt");

    for (int i=0; i<x; i++) {
        algorithm();
    }

ここで、 algorithm()は次のようなメソッドです。

private void algorithm () {
    for (int i=0; i<y; i++) {
        code.loc("some text");
        code.loc("other text");
        ...
    }

    // after "building" the code value I wrote it on the file
    fileOut.write(code.toString());
    fileOut.flush();
    code.free(); // this call "empties" the code variable (so the next time algorithm() is called it has the code var sets to "" - it frees a lot of memory)
                 // basically it calls "setLength(0)" method of StringBuilder
}

大きなテキストファイルでこれらすべてを実行すると、実行に約4500ミリ秒かかり、メモリは60MB未満になります。

次に、この他のコードを使用しようとしました。2番目のコード:

private SourceCodeBuilder code = new SourceCodeBuilder();

[...]

    // create "file.txt" and call algorithm
    fileOut = new FileWriter("file.txt");

    for (int i=0; i<x; i++) {
        algorithm();
    }

    fileOut.write(code.toString());
    fileOut.flush();
    fileOut.close();

今回のalgorithm()は次のようなメソッドです。

private void algorithm () {
    for (int i=0; i<y; i++) {
        code.loc("some text");
        code.loc("other text");
        ...
    }
}

250MB以上のメモリが必要です(コード変数で「free()」メソッドを呼び出さないので問題ありません。同じ変数で「continuos」追加です)が、驚くべきことに5300ms以上かかります。実行する。これは最初のコードよりも約16%遅く、その理由を自分自身に説明することはできません。

最初のコードでは、「file.txt」に小さなテキストを複数回書き込みます。2番目のコードでは、「file.txt」に大きなテキストを1回だけ記述し、より多くのメモリを使用しています。2番目のコードでは、より多くのメモリ消費を期待していましたが、CPU消費はさらに多くはありませんでした(I / O操作が多いという理由だけで)。

結論:最初のコードが2番目のコードよりも多くのI / O操作を実行する場合でも、最初のコードは2番目のコードよりも高速です。なんで?私は何かが足りないのですか?

4

2 に答える 2

4

すべてのシステムコールにはオーバーヘッドがあり、BufferedWriter、リーダー、またはストリームを使用することで回避できます。(これがバッファリングを使用する理由です)

最初のケースでは、コンテンツを書き込む前にコンテンツ全体をバッファリングしています。2番目のケースでは、一度に少しずつファイルを書き込んでいるため、システムコールが増え、オーバーヘッドが増えます。

ファイルをより速く生成する場合、ほとんどすべての時間がシステムコールに費やされていることに気付くかもしれません。

(バッファリングを使用して)ブロックでデータをストリーミングする理由は、それほど多くのメモリを使用しないようにするためです。つまり、バッファが大きくなると、役立つのではなく速度が低下するポイントがあります。

あなたの場合、StringBuilderまたはStringWriter(StringBufferを使用)に書き込んでいると思われます。これは、最終的に必要なサイズにサイズ変更されるため、コピーする必要があります。これにより、GCのオーバーヘッドが少し発生し、コピーも多くなります。

于 2012-06-28T14:38:23.260 に答える
3

大きなメモリバッファをゆっくりといっぱいにすると、コンテンツ全体をメモリ内の新しい場所にコピーするたびにバッファを複数回再割り当てする必要があるため、それに必要な時間は非線形に長くなります。特にバッファが200MB以上の場合、これには時間がかかります。バッファを事前に割り当てると、プロセスが速くなる可能性があります。

ただし、上記はすべて私の推測です。アプリケーションのプロファイルを作成して、追加の時間が実際にどこに行くのかを確認する必要があります。

于 2012-06-28T14:38:36.183 に答える