fwrite() - 大小和计数对性能的影响
Posted
技术标签:
【中文标题】fwrite() - 大小和计数对性能的影响【英文标题】:fwrite() - effect of size and count on performance 【发布时间】:2012-05-20 19:54:34 【问题描述】:对于 fwrite() 中两个参数 'size' 和 'count' 的用途,似乎存在很多混淆。我正在尝试找出哪个会更快 -
fwrite(source, 1, 50000, destination);
或
fwrite(source, 50000, 1, destination);
这是我代码中的一个重要决定,因为该命令将被执行数百万次。
现在,我可以直接跳到测试并使用结果更好的那个,但问题是代码适用于许多平台。
所以,
我怎样才能得到一个明确的答案,哪个跨平台更好?
fwrite() 的实现逻辑会因平台而异吗?
我知道有类似的问题(What is the rationale for fread/fwrite taking size and count as arguments?、Performance of fwrite and write size),但请理解这是关于同一问题的不同问题。在这种情况下,类似问题的答案是不够的。
【问题讨论】:
我只是在OS-X上做了一些测试,写了10个100MB的文件,参数顺序没有区别,或者用write(2)代替fwrite。至于其他平台,我就不好说了。 【参考方案1】:性能不应取决于任何一种方式,因为任何实现 fwrite 的人都会将大小和计数相乘以确定要执行多少 I/O。
FreeBSD 的 fwrite.c
的 libc 实现就是一个例子,它的全部内容是(包括省略的指令):
/*
* 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);
【讨论】:
我在几个平台上进行了测试,并查看了其他一些平台的 fwrite 源代码,它们中的任何一个都没有性能差异。谢谢!【参考方案2】:如果您考虑返回值,两个参数的用途会更清楚,它是成功写入/读取到/从流中的对象的计数:
fwrite(src, 1, 50000, dst); // will return 50000
fwrite(src, 50000, 1, dst); // will return 1
虽然速度可能取决于实现,但我预计不会有任何显着差异。
【讨论】:
同意。特别是,第一个将失败,如果它只得到 49999 字节(返回 0);如果这是它读取的字节数,第二个将返回 49999。因此,如果您的数据严格来说是 50,000 字节,那么您使用的数据一点也不重要。如果您的数据不是固定的但可能更短,那么您需要更灵活的选项。 我错误地使用了fread
而不是fwrite
,但同样的原则也适用。【参考方案3】:
我想向您指出my question,它最终暴露了调用fwrite
和多次调用fwrite
以“分块”写入文件之间的一个有趣的性能差异。
我的问题是微软的 fwrite 实现中存在一个错误,因此无法在一次调用中写入大于 4GB 的文件(它挂在fwrite
)。所以我不得不通过分块写入文件来解决这个问题,在循环中调用fwrite
,直到数据被完全写入。我发现后一种方法的返回速度总是比单个 fwrite
调用快。
我使用的是具有 32 GB RAM 的 Windows 7 x64,这使得写入缓存非常激进。
【讨论】:
以上是关于fwrite() - 大小和计数对性能的影响的主要内容,如果未能解决你的问题,请参考以下文章