Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.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 为什么Arrays.equals(char[],char[])比所有其他版本快8倍? 短篇小说_Java_Arrays_Performance_Optimization - Fatal编程技术网

Java 为什么Arrays.equals(char[],char[])比所有其他版本快8倍? 短篇小说

Java 为什么Arrays.equals(char[],char[])比所有其他版本快8倍? 短篇小说,java,arrays,performance,optimization,Java,Arrays,Performance,Optimization,根据我对几个不同Oracle和OpenJDK实现的测试,它似乎比其他类型的所有其他变体快8倍 如果应用程序的性能与比较数组是否相等密切相关,这意味着您非常希望将所有数据强制转换为char[],以获得这一神奇的性能提升 长话短说 最近,我正在编写一些高性能代码,用于比较用于索引到结构中的键。键可能相当长,并且通常只在后面的字节中不同,因此此方法的性能非常重要 有一次,我使用了char[]类型的键,但作为推广服务的一部分,为了避免从byte[]和ByteBuffer的底层源中复制一些内容,我将其改

根据我对几个不同Oracle和OpenJDK实现的测试,它似乎比其他类型的所有其他变体快8倍

如果应用程序的性能与比较数组是否相等密切相关,这意味着您非常希望将所有数据强制转换为
char[]
,以获得这一神奇的性能提升

长话短说 最近,我正在编写一些高性能代码,用于比较用于索引到结构中的键。键可能相当长,并且通常只在后面的字节中不同,因此此方法的性能非常重要

有一次,我使用了
char[]
类型的键,但作为推广服务的一部分,为了避免从
byte[]
ByteBuffer
的底层源中复制一些内容,我将其改为
byte[]
。突然,许多基本操作的性能下降了约3倍。我追溯到上面提到的事实:
Arrays.equals(char[],char[])
似乎比所有其他
Arrays.equals()
版本享有特殊地位,包括语义相同的
short[]
(并且可以使用相同的底层代码实现,因为签名不会影响equals的行为)

因此,我编写了一个测试
数组的所有基本变量。equals(…)
1和
char[]
变量压碎所有其他变量,如上所示

现在,~8x阵列的这种优势并没有以同样的规模扩展到更小或更大的阵列,但它仍然更快

对于小型阵列,常数因素似乎开始占主导地位,而对于大型阵列,L2/L3或主内存带宽开始发挥作用(在前面的图中,您已经可以非常清楚地看到后一种效果,
int[]
尤其是
long[]
阵列在大型阵列中的性能开始下降)。下面是相同测试的一个示例,但使用较小的小阵列和较大的大阵列:

在这里,
char[]
仍然很重要,只是没有以前那么多。小数组(只有16个元素)的每元素时间大约是标准时间的两倍,这可能是由于函数开销:大约0.5 ns/元素时,
char[]
variant仍然只需要整个调用大约7.2纳秒,或者在我的机器上大约19个周期,因此少量的方法开销会大大减少运行时的开销(而且,基准测试开销本身就是几个周期)

在大端,缓存和/或内存带宽是一个驱动因素。
long[]
变体的时间几乎是
int[]
变体的2倍。
short[]
变体,尤其是
byte[]
变体的效率不是很高(它们的工作集仍然适合我机器的L3)

char[]
与其他所有类型的应用程序之间的差异非常大,对于依赖数组比较的应用程序来说(对于某些特定的域来说,这其实并不罕见),值得尝试将所有数据放入
char[]
中加以利用

给出了什么?是因为
char
是一些
String
方法的基础,所以得到了特殊的处理吗?这只是JVM优化方法在基准测试中受到重创的另一种情况,而不是将相同的(明显的)优化扩展到其他基本类型(特别是
short
,在这里是相同的)


0……甚至不是那么疯狂——考虑各种系统,例如依赖于(冗长)哈希比较来检查值是否相等,或者哈希图,其中键长或可变大小。 1我没有在结果中包括

boolean[]
float[]
double[]
或double,以避免图表混乱,但对于记录
boolean[]
float[]
执行与
int[]
相同的操作,而
double[]
执行与
long[]相同的操作
。根据类型的基本大小,这是有意义的


2我在这里说了一点。性能可能突然发生了变化,但我实际上没有注意到,直到我再次运行基准测试,在一系列其他变化之后,导致了痛苦的对分过程,我确定了因果变化。这是一个很好的理由来进行某种类型的性能测量连续集成。

因为对于ars、SSE3和4.1/4.2都非常擅长检查状态变化。JVM生成的字符操作代码更加优化,因为这正是Java在web应用程序中经常使用的。Java在优化其他类型的数据方面非常糟糕。这正是beast的本质

在Scala和GoSu中也可以观察到同样的行为。现在传输的大部分信息都是文本形式的,因此除非您修改JVM,否则它会针对文本进行调整。而且,正如Marco所提到的,它下面是一个固有的C函数,这意味着它直接映射到高性能矢量化指令,如SSE4.x,甚至AVX2,如果标准JVM已经改进了很多


说真的,SSE4.x没有将字符和字节视为等效的数据类型,这就是文本分析更快的原因。此外,对于8位整数,在AVX2之前,指令并不存在。

当我建议这是答案时,我可能会大发雷霆,但根据
数组#等于(char[],char[])
方法作为一个内在函数实现


最有可能是因为它在所有字符串比较中都非常关键。@Marco13 guess是正确的。HotSpot JVM对
数组.equals(char[],char[])
有(即特殊的手工编码实现),但对其他
数组.equals方法没有@State(Scope.Benchmark)
public class ArrayEquals {
    @Param("100")
    int length;

    short[] s1, s2;
    char[] c1, c2;

    @Setup
    public void setup() {
        s1 = new short[length];
        s2 = new short[length];
        c1 = new char[length];
        c2 = new char[length];
    }

    @Benchmark
    public boolean chars() {
        return Arrays.equals(c1, c2);
    }

    @Benchmark
    @Fork(jvmArgsAppend = {"-XX:+UnlockDiagnosticVMOptions", "-XX:DisableIntrinsic=_equalsC"})
    public boolean charsNoIntrinsic() {
        return Arrays.equals(c1, c2);
    }

    @Benchmark
    public boolean shorts() {
        return Arrays.equals(s1, s2);
    }
}
Benchmark                     (length)  Mode  Cnt   Score   Error  Units
ArrayEquals.chars                  100  avgt   10  19,012 ± 1,204  ns/op
ArrayEquals.charsNoIntrinsic       100  avgt   10  49,495 ± 0,682  ns/op
ArrayEquals.shorts                 100  avgt   10  49,566 ± 0,815  ns/op
Benchmark                     (length)  Mode  Cnt   Score   Error  Units
ArrayEquals.chars                  100  avgt   10  18,931 ± 0,061  ns/op
ArrayEquals.charsNoIntrinsic       100  avgt   10  19,616 ± 0,063  ns/op
ArrayEquals.shorts                 100  avgt   10  19,753 ± 0,080  ns/op