文件大小为 300MB(最大)的高性能文件 I/O java API

Posted

技术标签:

【中文标题】文件大小为 300MB(最大)的高性能文件 I/O java API【英文标题】:High Performance File I/O java API for file size of 300MB (max) 【发布时间】:2018-05-20 02:35:28 【问题描述】:

构建应用程序,仅用于文件 I/O(可以是 pdf、jpg 等)。最大文件大小可以是 300MB。应用程序将部署在 64 位 Linux 上。 尝试了传统的阻塞 IO(FileOutputStream 等)。但我正在寻找具有良好性能的非阻塞或更好的方法。

这是我现在正在使用的代码。

FileOutputStream imageOutFile = new FileOutputStream("path/filename");
imageOutFile.write(byteArray);
imageOutFile.close();

请帮助我更好的方法,代码 sn-p 来满足这种情况。 休息服务将作为文件元数据的输入和字节流作为我的服务的输入。

【问题讨论】:

您能否至少自己对这个主题进行一些研究和/或解释您期望的什么样的结果?根据不同的领域,您的“高性能”标准可能是 2 毫秒或 400 毫秒。不幸的是,在那种状态下,没有人会正确回答你。 文件中包含的数据的目的地是什么?内存?一个 ZIP 文件?一个jar文件?一个 GZIP 文件?不同的存档文件?不同的/新文件?一个插座?其他输出目的地? 首先,文件读写性能很大程度上取决于您的存储设备。 300 MB 不算大,但也很大! @swaroop 看看AsynchronousFileChannel 以及如何将它们与CompletableFuture 一起使用,这应该会让您长期受益,还可以尝试在这个平台上提出更具体的问题。比如如何在 Completable future 中使用异步通道等。 @amritanshu 你的反应很好,我会给你的,但我想指出,如果他能够解释想要“如何使用异步通道与 Completable future 等” 。”如果他自己还不知道的话,他就会求助于谷歌来寻找答案。 :P +1 虽然。 【参考方案1】:

我建议使用内存映射文件。我们已将它们用于对高达 40 倍主内存大小的数据集进行快速、共享的读/写访问。

你可以使用 RandomAccessFile 中的 MappedByteBuffer 计划,或者使用像我这样的库。

低级文件内存访问

https://github.com/OpenHFT/Chronicle-Bytes/blob/master/src/test/java/net/openhft/chronicle/bytes/MappedMemoryTest.java

基于内存映射文件的仅附加队列/日志。 https://github.com/OpenHFT/Chronicle-Queue

基于内存映射文件的键/值存储。 https://github.com/OpenHFT/Chronicle-Map

作为参考,我使用的上述代码花费了大约 75 毫秒来编写一个 25Mb 的 pdf 文件。

我假设您的意思是 25 MB(兆字节)而不是 Mb(兆位),这意味着 333 MB/s 对于单个桌面 SSD 来说是合理的。也就是说,问题很可能是您的磁盘子系统可以做的极限工作。

顺便说一句,您可以以不到 1000 美元的价格购买速度可达 2 GB/s 的 NVMe 驱动器。

【讨论】:

如果你很少有非常大的文件可以一次又一次地访问,内存映射文件非常好(并且有很多空闲时间)。如果它是一个文件服务器,它真的会带来任何额外的优势吗?它也使清理变得棘手。为什么不直接缓存缓冲区以供前 K 访问呢? @amritanshu 如果 OP 正在创建和关闭大量文件,那么您是对的,内存映射无济于事,可能会使事情变得更复杂。我认为如果底层磁盘子系统在这种情况下您需要更快的磁盘,则访问模式更有可能接近极限。 这不切实际,除非你事先知道每张图片的确切输出尺寸。 @EJP 我提到的两种解决方案,Queue 和 Map,您不需要提前知道确切的大小,并且可以有效地处理几个字节到 1 GB 之间的任何内容。【参考方案2】:

您需要对现有代码做的就是使用BufferedOutputStream,因此:

OutputStream imageOutFile = new BufferedOutputStream(new FileOutputStream("path/filename"));

这将产生重大影响。

完全没有理由相信非阻塞 API 会更快,即使它存在于 Java 中的文件 I/O 中,但事实并非如此。

如果您事先确切知道输出大小,则可以使用MappedByteBuffer,但您不知道,所以您不能。

【讨论】:

@downvoter 请解释一下。这种事情并没有激起我在这里发帖的热情。 我没有投反对票,我的名声很差,但性能和速度之间还是有区别的。异步代码比阻塞代码性能更高,并且 AsynchronousFileChannel 确实使用操作系统的本机接口,因此确实存在一个异步文件 IO 库。 @amritanshu 请解释一下性能和更快的区别,让我向你解释一下非阻塞和异步 I/O 是两个不同的东西,而不是同一个东西的两个名称。否则,例如,您将不会同时拥有 SocketChannelAsynchronousSocketChannel。 Java 中没有非阻塞的FileChannel 变体。 AsynchronousFileChannel 有没有请检查一下。性能可以是延迟/响应能力的衡量标准,也可以只是吞吐量 MBps。异步 IO 可带来更好的响应能力,而不会对吞吐量产生负面影响。虽然我确信可能没有非阻塞文件库,但它的实用性没有实际意义。 @amritanshu 我怀疑问题是 close() 上文件的隐式刷新对于一个 21 MB 的文件,如果它具有合理的块大小,你如何编写并不重要。

以上是关于文件大小为 300MB(最大)的高性能文件 I/O java API的主要内容,如果未能解决你的问题,请参考以下文章

如何验证多个文件的最大文件大小为每个文件 2 mb? (验证)

仓库体积过大,如何减小?

pandas pytables 追加:性能和文件大小的增加

数据流作业 GCS 到 Pub/sub 最大批量大小

qt c ++中反序列化地图的大小增加

在golang磁盘写入性能