Java:对巨大磁盘文件进行随机读取的最快方法

我有一个中等大小的数据集,大约800 MB左右,这基本上是一些大的预计算表,我需要将一些计算速度提高几个数量级(创建该文件需要几个mutlicores计算机天来使用优化生成和multithreading算法……我真的需要那个文件)。

现在已经计算了一次,那么800MB的数据是只读的。

我无法忍受它在记忆中。

截至目前,它是一个巨大的800MB文件,但如果可以提供帮助,拆分成较小的文件不是问题。

我需要在该文件中读取大约32位数据的大量时间。 我不知道在哪里我需要读取这些数据:读取是均匀分布的。

在这样的文件或文件中随机读取Java的最快方法是什么? 理想情况下,我应该从几个不相关的线程中进行这些读取(但如果需要,我可以在单个线程中对读取进行排队)。

Java NIO是可行的吗?

我不熟悉’内存映射文件’:我想我不想在内存中映射800 MB。

我想要的是我可以访问这些800MB基于磁盘的数据的最快随机读取。

顺便说一下,如果人们想知道这与我不久前提出的问题完全不同:

Java:基于磁盘的快速哈希集

加载和存储在内存中的800MB并不多。 如果你有能力让多核机器在数据集上连续几天被剥夺,那么你可以支付额外的GB或两个RAM,不是吗?

也就是说,阅读Java的java.nio.MappedByteBuffer 。 从您的评论中可以清楚地看出“我认为我不想在内存中映射800 MB”这个概念并不清楚。

在坚果shell中, 映射的字节缓冲区允许以编程方式访问内存中的数据,尽管它可能在磁盘上或内存中 –这是由操作系统决定的,因为Java的MBB基于操作系统的虚拟内存子系统。 它也很好而且快速。 您还可以安全地从多个线程访问单个MBB。

以下是我建议您采取的步骤:

  1. 实例化将数据文件映射到MBB的MappedByteBuffer。 创作有点贵,所以保持它。
  2. 在你的查找方法……
    1. 实例化一个byte[4]数组
    2. 调用.get(byte[] dst, int offset, int length)
    3. 字节数组现在将拥有您的数据,您可以将其转换为值

并且presto! 你有你的数据!

我是MBB的忠实粉丝,过去曾成功地将它们用于此类任务。

RandomAccessFile(阻塞)可能有所帮助: http : //java.sun.com/javase/6/docs/api/java/io/RandomAccessFile.html

您还可以使用FileChannel.map()将文件区域映射到内存,然后读取MappedByteBuffer

另见: http : //java.sun.com/docs/books/tutorial/essential/io/rafs.html

实际上800 MB不是很大。 如果您有2 GB或更多内存,则它可以驻留在磁盘缓存中(如果不在您的应用程序本身中)。

对于写案例,在Java 7上,应该查看AsynchronousFileChannel。

在NTFS上对大文件执行随机面向记录的写入(超出物理内存,因此高速缓存没有帮助)时,我发现AsynchronousFileChannel在单线程模式下执行的操作数量是普通FileChannel的两倍(在10GB上)文件,160字节记录,完全随机写入,一些随机内容,基准测试循环的几百次迭代以实现稳定状态,大约每秒5,300次写入)。

我最好的猜测是,因为异步io归结为Windows 7中重叠的IO,所以NTFS文件系统驱动程序能够在每次调用后不必创建同步点时更快地更新自己的内部结构。

我对RandomAccessFile进行了微基准测试,看看它将如何执行(结果非常接近FileChannel,并且仍然是AsynchronousFileChannel性能的一半。

不确定multithreading写入会发生什么。 这是在Java 7上,在SSD上(SSD比磁性快一个数量级,在适合内存的较小文件上快一个数量级)。

看看Linux上是否存在相同的比率将会很有趣。