【问题标题】:file IO performance C文件 IO 性能 C
【发布时间】:2013-01-31 15:34:22
【问题描述】:


我有一个关于文件 IO(C 语言)及其性能问题的问题。

我有一个执行大量文件 I/O 的应用程序(在其生命周期内大约 3-6 小时,大约 0.5-0.75TB,主要是文件输出)。 目前我的应用程序sprintf()s 将所有内容转换为一个字符字符串,并在write()s 行的末尾转换为file_descriptor。我的字符串长度为 1024 个字符,但可以在 64 到 1024 之间变化。无论如何。

问题是:
在执行write() 之前先将一个更大的字符字符串(比如1MB?)和sprintf() 全部放入其中是否更有意义?或者,假设缓冲由write() 负责,那么完全直接跳过write() 到文件中是否更有意义?

我想到了一些东西,但不确定它是否真的会在性能方面取得任何成就:
如果我有一个结构来存储字符串、数字和字符串的各个部分,并改为对结构执行 mem_copy 呢?我猜类似于二进制写入?

我正在尝试实现“缓冲”方法或任何可以最大限度提高性能的方法。 后者是我需要使用该文件进行进一步处理。 有什么建议吗?

编辑
我与printf(); + redir 和sprintf(); write(); 做了一些简单的性能比较
我只是将~20GB 复制到一个文件中。

char string[1024];

for(i=0;i<(1<<20)*20;i++)
  printf("%s",string);

~/tmp/tests$ time ./printf.out > testing
real   2m22.101s
user   0m28.214s
sys    0m29.294s

相对于:

char string14[256]; ...etc
for(i=0;1<<(1<<20)*20;i++){
  sprintf(dst_string,"%s%s",dst_string, string14);
  sprintf(dst_string,"%s%s",dst_string, string24);
  sprintf(dst_string,"%s%s",dst_string, string34);
  sprintf(dst_string,"%s%s",dst_string, string44);
  write(fd, dst_string, 1024);
}

~/tmp/tests$ time ./write.out 

real   1m48.206s
user   0m58.544s
sys    0m41.079s

多个sprintf()s的原因是模拟copy->buffer再写buffer。 时间(无论如何都是真实的)并不像某些 cmets 所暗示的那样微不足道。当然这是一个简单的例子,也许在计算 + IO 的方案中可能不会。

在 printf 示例中我有点困惑,额外的时间都去哪儿了?用户+系统不加起来是真实的,他们至少不应该在球场上吗?因为缺了整整 1:30m。

此测试是否显示任何结论? sprintf + write > 简单地打印+redir?

无论如何,谢谢大家的cmets。

【问题讨论】:

  • 仅使用printf 可能(几乎可以肯定)优于sprintf,然后是write。
  • 你不应该假设缓冲是由write处理的。实际上,您应该假设 write 根本没有缓冲。
  • 但这会写入标准输出,我必须重定向它,这很慢,受终端限制,不是吗?哦,我没有可用的 fprintf。
  • 操作系统会为您完成大部分缓冲工作。要真正了解发生了什么,请查看操作系统文档。
  • 重定向并不慢,为什么你认为它是'受终端限制'?它是从一个进程到另一个进程的管道。

标签: c io


【解决方案1】:

当我在我的机器上进行一些测试时,我从不那么现代的硬件中获得了大约 60MB/s 的速度。那是 3.6GB/分钟或每小时 216GB(所以 3 小时产生大约 640GB)。我希望在您的应用程序中花费的时间主要是“等待磁盘”,在这种情况下,您使用什么 IO 方法绝对没有区别。

但就像所有性能问题一样,这不是您可以通过在互联网上询问或在书中查找或其他任何方式找到的答案。它必须在您关注的系统上进行测量。将我的旧硬盘更换为一些配置良好的 RAID,你会获得更好的性能 [如果它是正确的 RAID 系统 - 有些比单个磁盘慢,因为目的不是加快访问速度,而是确保可靠性]。

你也可以做一些比较: 1. 将软件的输出重定向到 /dev/null - 检查现在运行代码需要多长时间。如果它比您写入文件时快 10-100 倍,那么您知道您现在的写入方式或其他方法根本不会产生任何影响。 2. 使用dd if=/dev/zero of=yourfile bs=4k count=largenumber 创建类似大小的文件(大数 * 4KB = 典型文件大小) - 如果您的应用程序正在写入多个文件,则编写一个脚本来写入多个类似的不同文件)。如果这比您的应用程序快得多,那么通过改变您从应用程序输出的方式可以获得一些好处。

如果上述两件事中的任何一件表明有可能获得收益,那么请编写一些基准测试,以按照您希望应用程序工作的相同方式产生大量输出,看看有什么不同。一定要回来问问题。但我的猜测是,无论您对输出机制做什么,您的应用程序都不会运行得更快或更慢,因为这完全取决于“磁盘可以写入多快”。

【讨论】:

  • 调用 write 而不仔细选择缓冲区大小而不是使用标准工具可能会导致 I/O 中断,而使用精心设计的对 write 的调用可能会将性能提高 0.00001% (这会有所不同),因此说它“绝对没有区别”可能是不正确的。保证为每个字节调用write 会破坏性能!但所有合理的方案本质上都是等价的。
  • 是的,我倾向于故意避免在我的答案中过于迂腐,因为它实际上并没有多大帮助。最初的问题已经提到有 1KB 的块,这应该没问题 - 无论您采用哪种方式,操作系统中都有缓冲。
  • 感谢 cmets 伙计们,我想我必须对我的应用程序进行基准测试以查看调用 write() 的适当缓冲区。而且我看到了@WilliamPursell 的来源,事实上,即使是由于 IO 节省的少量时间,我也可能不会看到太大的改进。不过谢谢!
猜你喜欢
  • 1970-01-01
  • 2014-10-23
  • 2013-07-02
  • 2010-11-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多