【问题标题】:Random File Writing随机文件写入
【发布时间】:2016-09-06 01:09:20
【问题描述】:

如果我有多个线程生成文件块,写出块的最佳方法是什么?

ex) 5 个线程处理 500 个块的文件,块 0 不一定在块 1 之前完成,但磁盘上的输出文件需要按顺序排列。 (区块 0,区块 1,区块 2,……区块 499)

程序是 C++,fwrite() 能以某种方式“随机访问”文件吗?该文件是从头开始创建的,这意味着当块 5 完成时,由于块 1~4 尚未完成,文件可能仍为 0 大小。我可以直接写出第5块吗? (使用适当的 fseek)

这段代码对性能至关重要,所以我真的很好奇任何可以提高性能的东西。这看起来像一个多生产者(块生成器)和一个消费者(输出写入器)场景。思路案例是线程A完成前一个块后可以继续生成下一个块。

如果 fwrite 可以是“随机的”,那么输出写入器可以简单地获取输出,查找,然后写入。但是不确定这种设计是否可以大规模执行。

一些限制

  • 每个块大小相同,在内存中生成
  • 块大小是预先知道的,但不是块的总数。
  • 总大小为几 GB。很大。
  • 可能有多个作业在一台服务器上运行。每个工作都在上面进行了描述。他们有自己独立的生成器/写入器,不同的进程。
  • 服务器是 Linux/CentOS 机器。

【问题讨论】:

  • 块的大小都一样吗?
  • 为什么不在内存中组装文件并在完成后将其打印到磁盘?
  • fseek 你会找到的(尽管你可能希望在搜索之前积累至少几千字节的连续数据)。
  • 你应该能够 fseek + fwrite (如果你想并行化它,你可能需要原子地执行这两个调用),但在你这样做之前将文件扩展到所需的大小。这是假设事先知道文件的最终大小。 :)
  • 无法帮助您使用 Linux,但我发现标准库比 OS API 更慢且更不灵活。显然,你牺牲了便携性。我建议阅读 Linux API 提供的内容并尝试一下。内存映射文件可能是一种简单且高效的解决方案。

标签: c++ multithreading c++11 memory-mapped-files system-design


【解决方案1】:

假设每个块的大小相同,并且这些块是在需要写入磁盘之前在内存中生成的,那么 lseekwrite 的组合就可以了。

如果您能够一次写入整个块,则使用 fwrite 不会获得任何优势——所以只需直接使用 write——但是如果所有线程都需要某种锁定访问控制(互斥锁)共享同一个 fd —— 因为 seek+write 不能以原子方式完成,并且您不希望一个线程在第二个线程即将写入之前搜索。

这进一步假设您的文件系统是标准文件系统,而不是某种奇异的性质,因为并非所有输入/输出设备都支持lseek(例如管道)。

更新:lseek可以越过文件尾进行查找,只需设置whence参数= SEEK_SET和偏移到文件中的绝对位置即可(fseek也有同样的选项,但我没用过)。

【讨论】:

  • 如果我事先不知道总共有多少块,fseek可以工作吗?比如说如果第 5 块是第一个完成的,输出文件的大小仍然是 0,那它可以“fseek”到第 5 块的位置吗?
  • 谷歌一下。看来 fseek 超过 EOF 是没有问题的..!!!是的~~那么这是一个很好的候选解决方案。
  • 想知道为输出文件引入 Memory-Mapped-File 是否会获得额外的性能?
  • 你可以在文件结尾处寻找并开始写入——但是 Linux 和 Windows (FAT) 的行为略有不同,因为 Linux 支持带孔的文件,Windows(FAT) 将零写入填补漏洞——使其效率低下。
  • 我喜欢内存映射文件的很多方面,但它们很难调整以执行写入 - 但理论上它们应该与大多数应用程序的 write(2) 性能相同 -有些人声称他们应该更快,因为他们需要更少的数据副本(从用户到内核空间),但我从来没有看到这是一个真正的好处——但是你的 MMW
猜你喜欢
  • 1970-01-01
  • 2012-06-16
  • 2014-01-29
  • 1970-01-01
  • 1970-01-01
  • 2021-06-02
  • 2018-04-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多