25

fwrite()の2つの引数「size」と「count」の目的に関しては、多くの混乱があるようです。私はどちらが速くなるかを理解しようとしています-

fwrite(source, 1, 50000, destination);

また

fwrite(source, 50000, 1, destination);

このコマンドは何百万回も実行されるため、これは私のコードでは重要な決定です。

今、私はテストにジャンプして、より良い結果をもたらすものを使用することができましたが、問題は、コードが多くのプラットフォームを対象としていることです。

それで、

  • プラットフォーム間でどちらが優れているかについて、どうすれば決定的な答えを得ることができますか?

  • fwrite()の実装ロジックはプラットフォームごとに異なりますか?

同様の質問があることを認識しています(fread / fwriteがサイズとカウントを引数として取る理由は何ですか?fwriteとwriteサイズのパフォーマンス)が、これは同じ問題に関する別の質問であることを理解しています。この場合、同様の質問の回答では不十分です。

4

3 に答える 3

15

fwriteを実装する人は誰でもサイズとカウントを掛けて、実行するI / Oの量を決定するため、パフォーマンスはどちらの方法にも依存しないはずです。

これは、FreeBSDのlibc実装によって例示されfwrite.cており、全体として次のように読み取られます(省略されたディレクティブを含む)。

/*
 * Write `count' objects (each size `size') from memory to the given file.
 * Return the number of whole objects written.
 */
size_t
fwrite(buf, size, count, fp)
    const void * __restrict buf;
    size_t size, count;
    FILE * __restrict fp;
{
    size_t n;
    struct __suio uio;
    struct __siov iov;

    /*
     * ANSI and SUSv2 require a return value of 0 if size or count are 0.
     */
    if ((count == 0) || (size == 0))
        return (0);

    /*
     * Check for integer overflow.  As an optimization, first check that
     * at least one of {count, size} is at least 2^16, since if both
     * values are less than that, their product can't possible overflow
     * (size_t is always at least 32 bits on FreeBSD).
     */
    if (((count | size) > 0xFFFF) &&
        (count > SIZE_MAX / size)) {
        errno = EINVAL;
        fp->_flags |= __SERR;
        return (0);
    }

    n = count * size;

    iov.iov_base = (void *)buf;
    uio.uio_resid = iov.iov_len = n;
    uio.uio_iov = &iov;
    uio.uio_iovcnt = 1;

    FLOCKFILE(fp);
    ORIENT(fp, -1);
    /*
     * The usual case is success (__sfvwrite returns 0);
     * skip the divide if this happens, since divides are
     * generally slow and since this occurs whenever size==0.
     */
    if (__sfvwrite(fp, &uio) != 0)
        count = (n - uio.uio_resid) / size;
    FUNLOCKFILE(fp);
    return (count);
}
于 2012-05-12T14:35:46.933 に答える
15

ストリームとの間で正常に書き込まれた/読み取られたオブジェクトの数である戻り値を考慮すると、2つの引数の目的がより明確になります。

fwrite(src, 1, 50000, dst); // will return 50000
fwrite(src, 50000, 1, dst); // will return 1

速度は実装に依存する可能性がありますが、大きな違いはないと思います。

于 2012-05-12T15:01:21.927 に答える
2

私の質問を指摘したいと思います。その結果、ファイルを「チャンクで」書き込むために1回呼び出すことと複数回fwrite呼び出すことのパフォーマンスの興味深い違いが明らかになりました。fwrite

私の問題は、Microsoftのfwriteの実装にバグがあるため、4GBを超えるファイルを1回の呼び出しで書き込めないことでした(でハングしますfwrite)。fwriteそのため、ファイルをチャンクで書き込み、データが完全に書き込まれるまでループで呼び出すことで、これを回避する必要がありました。この後者のメソッドは、常に1回のfwrite呼び出しよりも速く返されることがわかりました。

私は32GBのRAMを搭載したWindows7x64を使用しているため、書き込みキャッシュはかなり積極的になります。

于 2014-02-24T00:58:17.370 に答える