【问题标题】:Fast writing: Memory-Mapped file versus BufferedWriter快速写入:内存映射文件与 BufferedWriter
【发布时间】:2012-10-11 12:59:39
【问题描述】:

有人对此进行了基准测试吗?我想尽可能快地写入磁盘,最大限度地减少写入调用的延迟。我想知道写入内存映射缓冲区(通过 buffer.put())是否比仅在 Java 端缓冲内容并在缓冲区已满后仅刷新到 fileChannel 更快。这样,一旦缓冲区已满,我将只进行系统调用(FileChannel.write)。我不确定当我将一些字节写入 MappedByteBuffer 时会发生什么,换句话说,是否完成了系统调用。

使用缓冲方法,我将能够以 16,32 或 64k 的块写入磁盘,我认为这是最佳的。缓冲的缺点是,如果应用程序崩溃,您必须有一个关闭挂钩来刷新内容。还有一层额外的复制到缓冲区,而不是直接写入文件通道。如果你拖尾文件,你可能看不到你想要的,因为内容被缓冲了。我也不知道如果尾随内存映射文件会发生什么。

有经验的人可以帮忙吗?

【问题讨论】:

  • 我没有对此进行基准测试,所以这是一个评论,但从我读过的所有内容来看,内存映射 IO 应该要快得多。

标签: java file-io io real-time nio


【解决方案1】:

如果您想尽量减少延迟,我发现写入 MemoryMappedFiles 会更快,因为它避免需要进行系统调用。这假设您不需要将数据强制写入磁盘,并且乐于让操作系统尽最大努力做到这一点。

写入 MemoryMappedFile 的典型延迟与写入内存相同,因此我不相信您会变得更快。随着文件的增长,您需要执行额外的内存映射区域,这可能需要 50 到 100 微秒,这很重要,但应该足够少,所以没关系。

通过系统调用写入 IO 大约需要 5 到 10 微秒,这对于更多应用程序来说已经足够快了,但如果需要的话,相对要慢得多。

如果您需要查看写入时低延迟的数据,我建议您查看我的库Java Chronicle,它支持从写入时开始以 100 ns 的典型延迟读取数据。

注意:虽然内存映射文件可以减少单个写入的延迟,但它不会增加磁盘子系统的写入吞吐量。这意味着,如果您的磁盘子系统速度较慢,您的内存很快就会耗尽(即使您有很多 GB),无论您采用哪种方法,这都将成为性能瓶颈。

例如,如果您有 SATA 或光纤,您可能有 500 MB/s 的限制,在这种情况下很容易超过,一旦您达到内存限制,无论您选择什么,这都会减慢您的速度。

【讨论】:

  • 谢谢,彼得。我的需求是低延迟,但我不太关心吞吐量。从理论上看,写入内存映射文件与写入另一个线程进行异步日志记录一样快,甚至更快,因为不需要同步,但实际上我已经看到异步日志记录要快得多。也许是因为我的non-blocking queue 速度超快,但我觉得我需要在这方面做更多的基准测试。我正在做的一件事是在每个日志之前暂停几个 ns 以降低吞吐量。这使它更快(~300ns)。
  • 我很想看看你的结果。我看到从进程 A 到进程 B 再到进程 A 的往返时间不到 200 ns,如果你发现的东西比我想知道的更快。
  • @TraderJoeChicago:内存映射有时必须同步关闭映射、扩展文件和重新打开映射。后台线程避免了这种情况。我猜这就是区别。
猜你喜欢
  • 1970-01-01
  • 2016-02-23
  • 2016-01-08
  • 2018-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-10
相关资源
最近更新 更多