2010-12-03 111 views
6

我正在写一个大型数值2维数组到二进制文件(最终大小〜75 MB)。fwrite和写入大小的性能

我在linux系统上这样做。首先,除了fwrite之外,还有更好的方法或系统调用来尽可能快地写入文件吗?其次,如果我应该使用fwrite,那么我应该只将整个文件写为1个连续的行吗?

fwrite(buf, sizeof(float), 6700*6700, fp); 

或写为一系列块

fwrite(buf, sizeof(float), 8192, fp); 
fwrite(*(buf+8192), sizeof(float), 8192, fp); 
.... 

,如果我要一块写的,有多大应该每块呢?

回答

5

只需使用fwrite(不需要进入较低级别的系统调用)并将其作为一个块执行。较低级别的系统调用将找出如何缓冲并最好地分割该写入命令。我从来没有能够在这样的事情上击败fwrite的表现 - 大量的顺序写入。

+0

我同意。我见过的唯一比标准fwrite()更好的文件是fwrite()到/ dev/shm上的一个文件:-) – Christoffer 2010-12-03 23:38:34

1

一个块更快。这有几个原因:

1)写入硬盘意味着还保持“最新”文件系统中的所有附加信息(时间戳,文件大小,使用的群集,锁等),所以有一些与每个文件访问相关的开销(尤其是写访问)。

2)磁盘I/O速度很慢,因此操作系统通常会尝试在其一侧实施一些缓存。这意味着每次使用文件I/O时,如果它被缓存,它应该被缓存等等,会有额外的检查。

1

你可以找到

http://sourceware.org/git/?p=glibc.git;a=blob;f=libio/iofwrite.c;hb=HEAD

FWRITE源正如你所看到的,这反过来要求IO_sputn,最终在

http://sourceware.org/git/?p=glibc.git;a=blob;f=libio/fileops.c;hb=HEAD

(具体_IO_new_file_xsputn结束)。正如你所看到的,这总是通过stdio缓冲区。

所以我建议不要使用stdio;直接使用write(2)写入将绕过这个额外的副本。

+0

或者用glibc提交bug报告。当数据大于缓冲区时通过缓冲区写入是荒谬的。 – 2010-12-04 03:54:52

+0

5年过去了,这仍然是真的吗? – 2015-11-02 18:17:57

2

通过使用nmap(),您可能会获得更高的性能,为您的数组创建空间(虚拟地址空间),然后写入“内存”而不是磁盘。

让系统为你做:它可能会分配尽可能少的页面,而这对于fwrite()转储的75 MB缓冲区不会发生。在一个CPU缓存受限的世界中,玩大缓冲区是一个不行(这就是为什么malloc()使用nmap()进行大分配的原因)。通过在设置nmap()时将缓冲区附加到文件中 - 在填充缓冲区之前,您可以将大量工作保存到系统中。

6

我同意miked和杰罗姆的大部分,但是...只适用于现代操作系统。如果您正在嵌入闪存文件系统,则有一些主要的例外。在这种环境下,如果您怀疑fwrite(),请使用write()与大块进行快速测试。

今天,我发现移动到write()的速度提高了4倍。这是由于嵌入式操作系统中的一个posix层,它将fwrite()转换为fputc()s ...在这种情况下,SYNC的底层flash文件就会出现乱码。 write()是由更靠近OS(Nucleus)的例程实现的,在这些例程中,块写入没有被分解为字节。

只是说......如果你质疑两个变种,可能最好还是try'em出来。