2012-05-12 66 views
16

对于fwrite()中两个参数'size'和'count'的用途似乎存在很多混淆。我试图找出这将是更快 -fwrite() - 大小和计数对性能的影响

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),但也明白,这是关于同一个问题不同的问题。类似问题的答案在这种情况下还不够。

+0

我刚刚在OS-X上做了一些测试,写了10个100MB的文件,参数的顺序和使用write(2)而不是fwrite之间没有区别。至于其他平台,我不能说。 –

回答

13

性能不应该依赖于任何一种方式,因为执行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); 
} 
+1

我在几个平台上运行了测试,并查看了其他某些平台的fwrite的源代码,其中没有任何性能差异。谢谢! –

12

的两个参数的目的变得更加清晰,如果你考虑疗法返回值,该表被成功写入对象的个数/读/从流:

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

的速度可能是执行相关的,虽然,我不希望任何相当大的损失差异。

+2

+1:特别是,如果它只获得49999字节(返回0),则第一个将失败;如果这是它读取的字节数,第二个将返回49999。因此,如果您的数据严格为50,000字节,那么您使用的并不重要。如果您的数据不是严格的但可能更短,那么您需要更灵活的选项。 –

+0

我错误地使用'fread'而不是'fwrite',但同样的原则也适用。 –

+0

@AlešKotnik随时编辑您的答案。 – Jens

2

我想你点my question,从而结束了暴露调用fwrite一次调用fwrite多次写“成块”文件之间的一个有趣的性能差异。

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

我在使用32 GB RAM的Windows 7 x64,这使得写入缓存非常积极。