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

Java 并行读取内存映射文件中的数据?,java,nio,mmap,Java,Nio,Mmap,如果映射的文件数据完全驻留在物理内存中,那么并行读取数据是否有任何好处?例如,通过使用开始/结束字节定义节数,并让单独的线程处理每个节?目标是允许频繁快速读取大二进制文件中的数据 我一直在做一些测试(JavaNIO),其中每个线程(使用4个线程进行测试)都可以访问mmap的引用,但由于每个线程都会更改mmap文件中的内部指针以读取下一组字节,所以这似乎不安全。我正在考虑为每个线程将一个文件分成4个MMAP块 更新: 为了提供更多的上下文,我最终要做的是有一个数据结构,它将引用多个mmaped文件

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

我一直在做一些测试(JavaNIO),其中每个线程(使用4个线程进行测试)都可以访问mmap的引用,但由于每个线程都会更改mmap文件中的内部指针以读取下一组字节,所以这似乎不安全。我正在考虑为每个线程将一个文件分成4个MMAP块

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

更新:
这适用于只读文件。

您可以为每个线程创建不同的文件通道。每个线程将读取不同的部分

如上所述,文件通道是线程安全的

你的代码应该是这样的

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();
        }
    }
}
   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();
            }

        }

    }
此代码在一个唯一线程中读取文件,您必须在可运行类中调整代码,并在构造函数或其他位置传递FileChannel大小,以并行读取整个文件,如本问题所述:

更新

不幸的是,MappedByteBuffer不是线程安全的,因为它是Buffer的一个子类,正如您在这里看到的:所以您必须使用同步机制来并行执行

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

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();
        }
    }
}
   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();
            }

        }

    }
私有类ThreadFileRead实现可运行{
私人决赛;
私人最终长尾;
公共线程文件读取(长ini,长端){
this.ini=ini;
this.end=end;
}
@凌驾
公开募捐{
MappedByteBuffer out=null;
试一试{
out=新的随机访问文件(“文件路径”、“r”)。
getChannel().map(FileChannel.MapMode.READ_ONLY,ini,end);
for(长i=ini;i
这似乎没有使用mmap。这种方法不是每次调用“read”方法时都需要从磁盘读取吗?是的。。。在每次调用中,此代码将从磁盘读取。。。让我看看这是否可以与mmapThank你,这是有帮助的。我在想,在最后,也许将文件划分为我想要的多个mmap是个好主意,存储对它们的引用,然后每次我需要读取时,将这些mmap引用传递给runnable。这有意义吗?这种方法的问题是,如果文件的某个区域被任何程序/线程更改,将引发意外的异常,因为文件更改在mmap中可见。您可以在这里看到:。如果您的文件从未被修改,这种方法是好的,在任何其他情况下,您将有意外的行为。如果在分割文件时复制它,就没有这些问题,我正在寻找只读解决方案。我在问题中也会提到这一点。