Java:对大型磁盘文件进行随机读取的最快方法
我有一个相当大的数据集,大约800 MB左右,基本上是一个大的预计算表,我需要将一些计算速度提高几个数量级(使用优化的多线程算法创建该文件花费了多台多处理器计算机数天的时间…我真的需要该文件) 现在已经计算了一次,800MB的数据是只读的 我记不住了 到目前为止,它是一个800MB的大文件,但如果能帮上忙的话,拆分成更小的文件并不是问题 我需要在文件中读取大约32位的数据。我不知道我需要在哪里读取这些数据:读取是均匀分布的 在Java中,对这样一个或多个文件进行随机读取的最快方法是什么?理想情况下,我应该从几个不相关的线程执行这些读取(但如果需要,我可以在单个线程中对读取进行排队) JavaNIO是一条出路吗 我不熟悉“内存映射文件”:我想我不想映射内存中的800MB 我想要的就是以最快的速度随机读取这些800MB的基于磁盘的数据 顺便说一句,如果人们怀疑这与我不久前提出的问题完全不同: 随机访问文件(阻塞)可能有助于: 您还可以使用Java:对大型磁盘文件进行随机读取的最快方法,java,nio,Java,Nio,我有一个相当大的数据集,大约800 MB左右,基本上是一个大的预计算表,我需要将一些计算速度提高几个数量级(使用优化的多线程算法创建该文件花费了多台多处理器计算机数天的时间…我真的需要该文件) 现在已经计算了一次,800MB的数据是只读的 我记不住了 到目前为止,它是一个800MB的大文件,但如果能帮上忙的话,拆分成更小的文件并不是问题 我需要在文件中读取大约32位的数据。我不知道我需要在哪里读取这些数据:读取是均匀分布的 在Java中,对这样一个或多个文件进行随机读取的最快方法是什么?理想情况
FileChannel.map()
将文件区域映射到内存,然后读取MappedByteBuffer
另请参见:实际上800 MB不是很大。如果您有2GB或更大的内存,它可以驻留在磁盘缓存中(如果不在应用程序本身中)。800MB的内存加载和存储量并不大。如果你能负担得起让多核机器连续几天对一个数据集进行翻录的话,你就能负担得起额外的一两GB内存,不是吗 也就是说,请阅读Java的。从您的评论“我想我不想映射内存中的800MB”中可以清楚地看出,这个概念并不清楚 简而言之,映射字节缓冲区允许用户以编程方式访问内存中的数据,尽管数据可能在磁盘或内存中——这由操作系统决定,因为Java的MBB基于操作系统的虚拟内存子系统。它也很好很快。您还可以从多个线程安全地访问单个MBB 以下是我建议您采取的步骤:
字节[4]
数组.get(字节[]dst,整数偏移量,整数长度)
我是MBB的忠实粉丝,过去曾成功地将其用于此类任务 对于Java 7上的写入情况,应查看AsynchronousFileChannel 在NTFS上跨大文件执行面向记录的随机写入时(超过物理内存,因此缓存并不是万能的),我发现AsynchronousFileChannel在单线程模式下执行的操作数是普通FileChannel的两倍(在一个10GB文件上,有160字节的记录,完全随机写入,一些随机内容,数百次基准测试循环迭代以达到稳定状态,大约每秒5300次写入) 我最好的猜测是,由于异步io在Windows 7中归结为重叠io,NTFS文件系统驱动程序能够更快地更新其内部结构,而不必在每次调用后创建同步点 我对RandomAccessFile进行了微基准测试,以了解它的性能(结果非常接近FileChannel,仍然是AsynchronousFileChannel性能的一半) 不确定多线程写入会发生什么情况。这是在Java 7上,在SSD上(SSD比magnetic快一个数量级,在适合内存的较小文件上快另一个数量级)
看看同样的比率在Linux上是否适用会很有趣。@Konrad Garus:好的,但这对我没有多大帮助:(我想知道的是,在800MB只读文件中随机读取的最快方式是什么(可能来自多个线程)。我认为nio(最后一个链接)RandomAccessFile和RandomAccessFile具有相似的性能,但使用不同的API。nio API有点复杂,但它可以是非阻塞的。两者都需要一个同步包装器来保证线程安全。难道没有办法将这些数据扔到一个数据库中,而该数据库经过了优化,可以完成这类工作吗?我假设它已经排序,并且您正在这样做二进制[或插值]搜索它,对吗?如果可能的话,你可以把它放进一个数据库中,这个数据库是为查询巨大的数据集而优化的,性能会更好。为什么你不能把它全部放进内存中呢?购买更多内存可能比编写代码来改善这种情况要便宜得多,而且它还有为其他事情提供更多内存的好处。。.800MB的内存现在真的不多了。你想将随机访问速度提高一个数量级。正如Jon所说,获得更多的RAM,或者如果不可能,使用固态驱动器。@Jon Skeet和JRL:遗憾的是,这是为部署在许多机器上的东西准备的……请确保将文件映射为只读-你不想让它成为意外事件对它的修改(显然,这在本机代码中是一个更大的问题)同意。而且我不确定让它读/写的并发性后果。