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

时间:2010-02-27 09:18:50

标签: java nio

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

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

我不能记住它。

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

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

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

Java NIO是可行的吗?

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

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

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

Java: fast disk-based hash set

4 个答案:

答案 0 :(得分:6)

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. 字节数组现在将包含您的数据,您可以将其转换为值
  3. 并且presto!你有你的数据!

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

答案 1 :(得分:2)

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

答案 2 :(得分:1)

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

答案 3 :(得分:1)

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

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

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

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

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

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