25

关于 fwrite() 中两个参数“size”和“count”的用途似乎有很多混淆。我试图弄清楚哪个会更快-

fwrite(source, 1, 50000, destination);

或者

fwrite(source, 50000, 1, destination);

这是我的代码中的一个重要决定,因为该命令将被执行数百万次。

现在,我可以直接跳到测试并使用能提供更好结果的那个,但问题是该代码适用于许多平台。

所以,

  • 我如何才能获得跨平台哪个更好的明确答案?

  • fwrite() 的实现逻辑会因平台而异吗?

我意识到有类似的问题(什么是 fread/fwrite 将大小和计数作为参数的理由?fwrite 和写入大小的性能),但请理解这是关于同一问题的不同问题。在这种情况下,类似问题的答案是不够的。

4

3 回答 3

15

如果您考虑返回值,则两个参数的目的会更清楚,它是成功写入/读取到流/从流中读取的对象的计数:

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

速度可能取决于实现,但我预计不会有任何显着差异。

于 2012-05-12T15:01:21.927 回答
15

性能不应该取决于任何一种方式,因为任何实现 fwrite 的人都会乘以 size 和 count 来确定要执行多少 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 回答
2

我想向您指出我的问题,它最终暴露了调用fwrite一次和fwrite多次调用以“分块”写入文件之间的一个有趣的性能差异。

我的问题是微软的 fwrite 实现中存在一个错误,因此无法在一次调用中写入大于 4GB 的文件(它挂在fwrite)。所以我不得不通过分块写入文件来解决这个问题,fwrite循环调用直到数据被完全写入。我发现后一种方法总是比单次fwrite调用返回得更快。

我在具有 32 GB RAM 的 Windows 7 x64 中,这使得写入缓存非常激进。

于 2014-02-24T00:58:17.370 回答