当前位置: 首页 > 知识库问答 >
问题:

比较直接和非直接ByteBuffer Get/Put操作

劳仲渊
2023-03-14

共有1个答案

邢炯
2023-03-14

从非直接bytebuffer获取/放入比从直接bytebuffer获取/放入更快吗?

如果将堆缓冲区与不使用本机字节顺序的直接缓冲区进行比较(大多数系统都是小endian,直接字节缓冲区的默认值是大endian),性能非常相似。

如果使用本机有序字节缓冲区,多字节值的性能会显著提高。对于byte,无论您做什么都没有什么区别。

public static void main(String... args) {
    ByteBuffer bb1 = ByteBuffer.allocateDirect(256 * 1024).order(ByteOrder.nativeOrder());
    ByteBuffer bb2 = ByteBuffer.allocateDirect(256 * 1024).order(ByteOrder.nativeOrder());
    for (int i = 0; i < 10; i++)
        runTest(bb1, bb2);
}

private static void runTest(ByteBuffer bb1, ByteBuffer bb2) {
    bb1.clear();
    bb2.clear();
    long start = System.nanoTime();
    int count = 0;
    while (bb2.remaining() > 0)
        bb2.putInt(bb1.getInt());
    long time = System.nanoTime() - start;
    int operations = bb1.capacity() / 4 * 2;
    System.out.printf("Each putInt/getInt took an average of %.1f ns%n", (double) time / operations);
}

印刷品

Each putInt/getInt took an average of 83.9 ns
Each putInt/getInt took an average of 1.4 ns
Each putInt/getInt took an average of 34.7 ns
Each putInt/getInt took an average of 1.3 ns
Each putInt/getInt took an average of 1.2 ns
Each putInt/getInt took an average of 1.3 ns
Each putInt/getInt took an average of 1.2 ns
Each putInt/getInt took an average of 1.2 ns
Each putInt/getInt took an average of 1.2 ns
Each putInt/getInt took an average of 1.2 ns

我很确定JNI调用需要的时间超过1.2 ns。

以证明导致延迟的不是“JNI”调用,而是它周围的废话。您可以直接使用Unsafe编写相同的循环。

public static void main(String... args) {
    ByteBuffer bb1 = ByteBuffer.allocateDirect(256 * 1024).order(ByteOrder.nativeOrder());
    ByteBuffer bb2 = ByteBuffer.allocateDirect(256 * 1024).order(ByteOrder.nativeOrder());
    for (int i = 0; i < 10; i++)
        runTest(bb1, bb2);
}

private static void runTest(ByteBuffer bb1, ByteBuffer bb2) {
    Unsafe unsafe = getTheUnsafe();
    long start = System.nanoTime();
    long addr1 = ((DirectBuffer) bb1).address();
    long addr2 = ((DirectBuffer) bb2).address();
    for (int i = 0, len = Math.min(bb1.capacity(), bb2.capacity()); i < len; i += 4)
        unsafe.putInt(addr1 + i, unsafe.getInt(addr2 + i));
    long time = System.nanoTime() - start;
    int operations = bb1.capacity() / 4 * 2;
    System.out.printf("Each putInt/getInt took an average of %.1f ns%n", (double) time / operations);
}

public static Unsafe getTheUnsafe() {
    try {
        Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafe.setAccessible(true);
        return (Unsafe) theUnsafe.get(null);
    } catch (Exception e) {
        throw new AssertionError(e);
    }
}
Each putInt/getInt took an average of 40.4 ns
Each putInt/getInt took an average of 44.4 ns
Each putInt/getInt took an average of 0.4 ns
Each putInt/getInt took an average of 0.3 ns
Each putInt/getInt took an average of 0.3 ns
Each putInt/getInt took an average of 0.3 ns
Each putInt/getInt took an average of 0.3 ns
Each putInt/getInt took an average of 0.3 ns
Each putInt/getInt took an average of 0.3 ns
Each putInt/getInt took an average of 0.3 ns
 类似资料:
  • 问题内容: 从非直接字节缓冲区获取/输入比从直接字节缓冲区获取/输入更快吗? 如果我必须从直接字节缓冲区读取/写入,最好先读取/写入线程本地字节数组,然后再用字节数组完全更新(用于写入)直接字节缓冲区吗? 问题答案: 从非直接字节缓冲区获取/输入比从直接字节缓冲区获取/输入更快吗? 如果将堆缓冲区与不使用本机字节顺序的直接缓冲区进行比较(大多数系统为低字节序,直接字节缓冲区的默认值为大字节序),则

  • AWS Direct Connect允许从我们的网络到AWS位置创建专用网络连接。 它使用802.1q VLAN,可以将其划分为多个虚拟接口,以使用相同的连接访问公共资源。 这导致网络成本降低和带宽增加。 可以根据需要随时重新配置虚拟接口。 使用AWS Direct Connect的要求 我们的网络必须满足以下条件之一才能使用AWS Direct Connect - 我们的网络应位于AWS Dir

  • 问题内容: 如果我使用像这样的比较(a是int,b和c是float / double)是否安全: 它可能听起来很荒谬,但是在我的旧编程语言中,有时1 + 2 == 3是错误的(因为左侧返回2.99999999999 …)。而且,这呢: 问题答案: 通常,由于不能精确地将许多十进制数字表示为or 值,因此这样做并不安全。经常陈述的解决方案是测试数字之间的差异是否小于某个“小”值(在数学文献中通常用希

  • 主要内容:直接量的类型,直接量的赋值直接量是指在程序中通过源代码直接给出的值,例如在 代码中,为变量 a 所分配的初始值 5 就是一个直接量。 直接量的类型 并不是所有的数据类型都可以指定直接量,能指定直接量的通常只有三种类型:基本类型、字符串类型和 null 类型。具体而言, Java 支持如下 8 种类型的直接量。 1)int 类型的直接量 在程序中直接给出的整型数值,可分为二进制、十进制、八进制和十六进制 4 种,其中二进制需

  • 当我在浏览上面的接口时,在阅读了许多相同主题的站点后,我对这些接口的语法不是很清楚。 请考虑以下代码段: 如果每个查询都是可理解的。

  • 基类既可能是派生类的直接基类,也可能是派生类的间接基类。在声明派生类时,派生类的首部要显式地列出直接基类。间接基类不是显式地列在派生类的首部,而是沿着类的多个层次向上继承。