并行读取内存映射文件中的数据?

时间:2015-11-22 18:02:21

标签: java nio mmap

如果映射文件数据完全驻留在物理内存中,那么并行读取数据有什么好处,例如通过定义具有开始/结束字节的段数并且每个段都有单独的线程?目标是允许频繁快速读取大二进制文件中的数据。

我一直在做一些测试(Java NIO),其中每个线程(使用4个线程进行测试)都可以访问mmap的引用,但由于每个线程都在mmaped文件中更改内部指针以读取下一组字节,因此不会# 39;看起来很安全。我考虑过为每个线程将文件分成4个mmaped块?

更新: 为了给出更多的上下文,我最后要做的是拥有一个数据结构,该数据结构将引用mmaped文件的数量,以便那些引用可以提供给某些函数,这些函数将对值进行循环扫描测试并将它们放入进入字节缓冲区。

更新: 这是针对只读文件的。

1 个答案:

答案 0 :(得分:1)

您可以为每个线程创建不同的FileChannel。每个线程将读取不同的部分。

正如documentation所说,FileChannels是线程安全的。

您的代码将是这样的

package nio;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class HughTest {

    public static void main(String[] args) {

        try (FileChannel inChannel = new RandomAccessFile("file_Path", "r").getChannel()){

            // TODO Change in each thread the chunk size to read
            long fileSize = inChannel.size();
            ByteBuffer buffer = ByteBuffer.allocate((int) fileSize);
            inChannel.read(buffer);
            buffer.flip();
            // Do what you want

            inChannel.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

此代码在唯一线程中读取文件,您可以在可运行的类中调整代码,并在构造函数或其他位置传递FileChannel大小以并行读取整个文件,如此问题中所述:Can I seek a file from different threads independently using FileChannel?

<强>更新

不幸的是,MappedByteBuffer不是线程安全的,因为它是Buffer的子类,你可以在这里看到:Does memory mapped file support concurrent get/put?所以你必须使用同步机制才能并行执行。

一种方法是以时间方式复制整个文件(这样可以确保永远不会修改文件),然后使用像这样的可运行实现

   private class ThreadFileRead implements Runnable {

        private final long ini;
        private final long end;

        public ThreadFileRead(long ini, long end) {
            this.ini = ini;
            this.end = end;
        }

        @Override
        public void run() {
            MappedByteBuffer out = null;

            try {
                out = new RandomAccessFile("FILEPATH", "r").
                        getChannel().map(FileChannel.MapMode.READ_ONLY, ini, end);

                for (long i = ini; i < end; i++)
                {
                    // do work
                }


            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }

    }