Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java ByteBuffer性能问题_Java_Performance_Nio_Bytebuffer - Fatal编程技术网

Java ByteBuffer性能问题

Java ByteBuffer性能问题,java,performance,nio,bytebuffer,Java,Performance,Nio,Bytebuffer,在处理多个千兆字节的文件时,我注意到了一些奇怪的事情:似乎使用filechannel从一个文件读入一个使用allocateDirect分配的重用ByteBuffer对象要比从MappedBytebyBuffer读入慢得多,事实上,它甚至比使用常规读取调用读入字节数组还要慢 我希望它(几乎)和从MappedByteBuffer读取一样快,因为我的ByteBuffer是用allocateDirect分配的,因此读取应该直接在我的ByteBuffer中结束,而不需要任何中间副本 我现在的问题是:我做错

在处理多个千兆字节的文件时,我注意到了一些奇怪的事情:似乎使用filechannel从一个文件读入一个使用allocateDirect分配的重用ByteBuffer对象要比从MappedBytebyBuffer读入慢得多,事实上,它甚至比使用常规读取调用读入字节数组还要慢

我希望它(几乎)和从MappedByteBuffer读取一样快,因为我的ByteBuffer是用allocateDirect分配的,因此读取应该直接在我的ByteBuffer中结束,而不需要任何中间副本

我现在的问题是:我做错了什么?或者bytebuffer+filechannel真的比常规io/mmap慢吗

在下面的示例代码中,我还添加了一些将读取的内容转换为长值的代码,因为我的真实代码经常这样做。我希望ByteBuffer getLong()方法比我自己的byte Shuffler快得多

测试结果: mmap:3.828 bytebuffer:55.097 常规i/o:38.175

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.MappedByteBuffer;

class testbb {
    static final int size = 536870904, n = size / 24;

    static public long byteArrayToLong(byte [] in, int offset) {
        return ((((((((long)(in[offset + 0] & 0xff) << 8) | (long)(in[offset + 1] & 0xff)) << 8 | (long)(in[offset + 2] & 0xff)) << 8 | (long)(in[offset + 3] & 0xff)) << 8 | (long)(in[offset + 4] & 0xff)) << 8 | (long)(in[offset + 5] & 0xff)) << 8 | (long)(in[offset + 6] & 0xff)) << 8 | (long)(in[offset + 7] & 0xff);
    }

    public static void main(String [] args) throws IOException {
        long start;
        RandomAccessFile fileHandle;
        FileChannel fileChannel;

        // create file
        fileHandle = new RandomAccessFile("file.dat", "rw");
        byte [] buffer = new byte[24];
        for(int index=0; index<n; index++)
            fileHandle.write(buffer);
        fileChannel = fileHandle.getChannel();

        // mmap()
        MappedByteBuffer mbb = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, size);
        byte [] buffer1 = new byte[24];
        start = System.currentTimeMillis();
        for(int index=0; index<n; index++) {
                mbb.position(index * 24);
                mbb.get(buffer1, 0, 24);
                long dummy1 = byteArrayToLong(buffer1, 0);
                long dummy2 = byteArrayToLong(buffer1, 8);
                long dummy3 = byteArrayToLong(buffer1, 16);
        }
        System.out.println("mmap: " + (System.currentTimeMillis() - start) / 1000.0);

        // bytebuffer
        ByteBuffer buffer2 = ByteBuffer.allocateDirect(24);
        start = System.currentTimeMillis();
        for(int index=0; index<n; index++) {
            buffer2.rewind();
            fileChannel.read(buffer2, index * 24);
            buffer2.rewind();   // need to rewind it to be able to use it
            long dummy1 = buffer2.getLong();
            long dummy2 = buffer2.getLong();
            long dummy3 = buffer2.getLong();
        }
        System.out.println("bytebuffer: " + (System.currentTimeMillis() - start) / 1000.0);

        // regular i/o
        byte [] buffer3 = new byte[24];
        start = System.currentTimeMillis();
        for(int index=0; index<n; index++) {
                fileHandle.seek(index * 24);
                fileHandle.read(buffer3);
                long dummy1 = byteArrayToLong(buffer1, 0);
                long dummy2 = byteArrayToLong(buffer1, 8);
                long dummy3 = byteArrayToLong(buffer1, 16);
        }
        System.out.println("regular i/o: " + (System.currentTimeMillis() - start) / 1000.0);
    }
}
导入java.io.File;
导入java.io.IOException;
导入java.io.RandomAccessFile;
导入java.nio.ByteBuffer;
导入java.nio.channels.FileChannel;
导入java.nio.channels.FileChannel.MapMode;
导入java.nio.MappedByteBuffer;
类testbb{
静态最终整型尺寸=536870904,n=尺寸/24;
静态公共long byteArrayToLong(字节[]in,int偏移量){

当循环的迭代次数超过10000次时,返回(

此外,您可能希望将ByteBuffer的顺序设置为Order(ByteOrder.nativeOrder()),以避免在执行
getLong
时交换所有字节,并一次读取超过24个字节。(由于读取非常小的部分会生成更多的系统调用),请尝试一次读取32*1024个字节


我还尝试使用本机字节顺序对MappedByteBuffer执行
getLong
。这可能是最快的。

A
MappedByteBuffer
将始终是最快的,因为操作系统将操作系统级磁盘缓冲区与进程内存空间相关联。相比之下,首先读取分配的直接缓冲区将块加载到OS缓冲区中,然后将OS缓冲区的内容复制到分配的进程内缓冲区中

您的测试代码也会执行大量非常小(24字节)的读取。如果您的实际应用程序也这样做,那么您将从映射文件中获得更大的性能提升,因为每个读取都是一个单独的内核调用。通过映射,您应该可以看到性能提高了几倍


至于比java.io读取速度慢的直接缓冲区:您没有给出任何数字,但我预计会有一点下降,因为
getLong()
调用需要跨越JNI边界。

我相信您只是在进行微优化

下面是一个具有较大缓冲区和冗余
seek
/
setPosition
调用的版本

  • 当我启用“本机字节排序”(如果机器使用不同的“endian”约定,这实际上是不安全的):
  • 当我注释掉order语句并使用默认的大端排序时:
  • 您的原始代码:
代码如下:

导入java.io.File;
导入java.io.IOException;
导入java.io.RandomAccessFile;
导入java.nio.ByteBuffer;
导入java.nio.ByteOrder;
导入java.nio.channels.FileChannel;
导入java.nio.channels.FileChannel.MapMode;
导入java.nio.MappedByteBuffer;
类Testbb2{
/**同时缓冲大量长值*/
静态最终整型BUFFSIZE=0x800*8;//8192
静态最终整数数据大小=0x8000*BUFFSIZE;
静态公共long byteArrayToLong(字节[]in,int偏移量){

返回((长)(在[offset+0]和0xff中)读取直接字节缓冲区的速度更快,但将数据从中取出到JVM的速度更慢。直接字节缓冲区适用于您只是复制数据而没有在Java代码中实际查看数据的情况。这样,它就根本不必跨越本机->JVM边界,因此比使用字节[]更快数组或普通ByteBuffer,其中数据在复制过程中必须跨越该边界两次。

将代码移动到单独的方法中没有任何区别。在MappedBytBuffer中使用getLong确实使其速度更快。但我仍然想知道为什么第二个测试(“从文件通道读取ByteBuffer”)太慢了。\n您每24个字节执行一次系统调用。在第一个示例中,您总共只执行一次或两次系统调用。根据我所读的(在o'reilly的一本关于NIO的书中),对正确分配的bytebuffer的读取也应该是直接的,没有任何副本。不幸的是,将输入文件映射到内存在真正的应用程序中不起作用,因为它的大小可能是TB。这些数字在我的邮件底部:mmap:3.828秒bytebuffer:55.097秒常规i/o:38.175秒。@Folkert-作者之一这本书是错的,或者你误解了他/她说的话。磁盘控制器处理的是大数据块,操作系统需要一个地方来缓冲这些数据并分割出你需要的数据块。但真正的问题是,你的每一次读取——在NIO或IO中——都是一个单独的系统调用,而映射文件是一个直接内存访问(可能存在页面错误)。如果您的实际应用程序有很大比例的本地化读取,您可能会受益于缓冲区缓存(可以是内存映射或堆上的)。如果您要跳过一个TB级的文件,那么磁盘IO将成为限制因素,甚至内存映射也无济于事
mmap: 1.358
bytebuffer: 0.922
regular i/o: 1.387
mmap: 1.336
bytebuffer: 1.62
regular i/o: 1.467
mmap: 3.262
bytebuffer: 106.676
regular i/o: 90.903