0

各行に 5 つの要素がある CSV ファイルに大量のデータを記録する必要があります。私は行を格納するために大きなバッファを使用しfwrite(...)、それがいっぱいになったときにそれを一度にフラッシュし、必要になるまで繰り返しました。以下は、ロギング機能のスニペットです。

void logInFile(int a, int b, int c, int d, int e)
{    
    sprintf(rowInLog,"%d,%d,%d,%d,%d\n",a,b,c,d,e); 
    int bytesInRow = strlen(rowInLog);
    if(bytesInRow + bytesUsedInBuffer <= sizeOfBuffer)
    {
        strcat(buffer, rowInLog);
        bytesUsedInBuffer += bytesInRow;
    }
    else
    {
        printf("flushing file to disk\n");
        fwrite(buffer, bytesUsedInBuffer, 1, fp);
        memset(buffer, 0, sizeOfBuffer);
        bytesUsedInBuffer = 0;
        strcat(buffer, rowInLog);
        bytesUsedInBuffer += bytesInRow;
    }
}

しかし、これは実行を非常に遅くしています。 「ファイルをディスクにフラッシュしています」というメッセージが画面に表示されないため、フラッシュが原因ではありません。このロギング関数を呼び出さないと、プログラム全体が数分で実行されますが、これに伴い、2 時間でさえ完了しませんでした。他に根本的な欠陥はありますか?

4

2 に答える 2

3

私が疑うあなたの答えはここにあります:

if(bytesInRow + bytesUsedInBuffer <= sizeOfBuffer)
{
    strcat(buffer, rowInLog);  // <--- riiiight here.
    bytesUsedInBuffer += bytesInRow;
}

この関数は、呼び出すたびにstrcat()全体をスキャンして最後を見つけます。が大きく、ほぼ満杯の場合、かなり遅くなる可能性がありますbuffer。動作は、 のサイズでbufferおおよそ O(N 2buffer ) です。バッファーのサイズを大きくすると、パフォーマンスが急速に低下します。これは、バッファーに必要なものとはほとんど逆です。(編集:コメントで、バッファが1GBであると述べました。バッファがいっぱいになると、上記のコードは非常に遅くなると思います。)

ただし、終了位置とコピーするバイト数はす​​でに正確にわかっています。そのため、代わりに次のようにします。

if(bytesInRow + bytesUsedInBuffer <= sizeOfBuffer)
{
    memcpy(buffer + bytesUsedInBuffer, rowInLog, bytesInRow + 1);
    bytesUsedInBuffer += bytesInRow;
}

memcpyを操作する他の strXXX 関数が配置されている場合に備えて、バッファに NUL ターミネータを配置するために、余分なバイトを 1 つコピーしたことに注意してくださいbuffer。そうでない場合は、+ 1上記を安全に削除できます。

同様の、あまり深刻ではないエラーがelse句で発生します。これも次のように置き換えることができますmemcpy:

    printf("flushing file to disk\n");
    fwrite(buffer, bytesUsedInBuffer, 1, fp);
    memcpy(buffer, rowInLog, bytesInRow + 1);
    bytesUsedInBuffer = bytesInRow;

これらのステートメントを組み合わせることで、時間を少し節約することもできます。

sprintf(rowInLog,"%d,%d,%d,%d,%d\n",a,b,c,d,e); 
int bytesInRow = strlen(rowInLog);

は出力文字列のsprintf長さを返すので、次のように簡単に言えます。

int bytesInRow = sprintf(rowInLog,"%d,%d,%d,%d,%d\n",a,b,c,d,e); 

それはコードの主なパフォーマンスの問題ではありませんでしたが、それを変更するとさらに改善されます。


編集:さらに優れた代替アプローチ:

完全に排除したい場合は、次のmemcpy()代替アプローチを検討してください。

bytesUsedInBuffer += snprintf( buffer + bytesUsedInBuffer, maximumLineSize, 
                               "%d,%d,%d,%d,%d\n", a,b,c,d,e );

if (bytesUsedInBuffer >= sizeOfBuffer - maximumLineSize )
{
    fwrite(buffer, bytesUsedInBuffer, 1, fp);
    bytesUsedInBuffer = 0;
}

maximumLineSize60 など、5 つの整数の行に適切な値を設定します。

于 2013-12-22T19:54:34.127 に答える