文件大小为 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 是两个不同的东西,而不是同一个东西的两个名称。否则,例如,您将不会同时拥有SocketChannel
和 AsynchronousSocketChannel
。 Java 中没有非阻塞的FileChannel
变体。
AsynchronousFileChannel 有没有请检查一下。性能可以是延迟/响应能力的衡量标准,也可以只是吞吐量 MBps。异步 IO 可带来更好的响应能力,而不会对吞吐量产生负面影响。虽然我确信可能没有非阻塞文件库,但它的实用性没有实际意义。
@amritanshu 我怀疑问题是 close() 上文件的隐式刷新对于一个 21 MB 的文件,如果它具有合理的块大小,你如何编写并不重要。以上是关于文件大小为 300MB(最大)的高性能文件 I/O java API的主要内容,如果未能解决你的问题,请参考以下文章