如何才能快速比较两个字节数组呢?我将问题描述成下面的接口:
public int compareTo(byte[] b1, int s1, int l1, byte[] b2, int s2,int l2);
最直观的做法是同时遍历两个数组,两两比较。
public int compareTo(byte[] buffer1, int offset1, int length1, byte[] buffer2, int offset2, int length2) { // Short circuit equal case if (buffer1 == buffer2 && offset1 == offset2 && length1 == length2) { return 0; } // Bring WritableComparator code local int end1 = offset1 + length1; int end2 = offset2 + length2; for (int i = offset1, j = offset2; i < end1 && j < end2; i++, j++) { int a = (buffer1[i] & 0xff); int b = (buffer2[j] & 0xff); if (a != b) { return a - b; } } return length1 - length2; }
如果事情这么简单就结束了,就没有意思了。
如果要提升性能,可以做循环展开等等优化,但这些优化应该依赖JVM来做,新的JVM可以做的很好。那还有什么办法可以提高性能呢?
可以将字节数组合并!!上面的例子中,每个byte被迫转型成了int,再比较。其实我们可以将8个byte转换成一个long,在比较long,这样效果会不会好些?用什么方法转换才是最优的?
long sun.misc.Unsafe.getLong(Object o,int offset)
Java提供了一个本地方法,可以最快最好转换byte与long。该函数是直接访问一个对象的内存,内存地址是对象指针加偏移量,返回该地址指向的值。有人说Java很安全,不可以操作指针,所以有的时候性能也不高。其实不对,有了这个Unsafe类,Java一样也不安全。所以Unsafe类中的方法都不是public的,不过没关系,我们有反射。言归正传,下面是使用这种技术手段的实现代码。
public int compareTo(byte[] buffer1, int offset1, int length1, byte[] buffer2, int offset2, int length2) { // Short circuit equal case if (buffer1 == buffer2 && offset1 == offset2 && length1 == length2) { return 0; } int minLength = Math.min(length1, length2); int minWords = minLength / Longs.BYTES; int offset1Adj = offset1 + BYTE_ARRAY_BASE_OFFSET; int offset2Adj = offset2 + BYTE_ARRAY_BASE_OFFSET; /* * Compare 8 bytes at a time. Benchmarking shows comparing 8 * bytes at a time is no slower than comparing 4 bytes at a time * even on 32-bit. On the other hand, it is substantially faster * on 64-bit. */ for (int i = 0; i < minWords * Longs.BYTES; i += Longs.BYTES) { long lw = theUnsafe.getLong(buffer1, offset1Adj + (long) i); long rw = theUnsafe.getLong(buffer2, offset2Adj + (long) i); long diff = lw ^ rw; if (diff != 0) { if (!littleEndian) { return (lw + Long.MIN_VALUE) < (rw + Long.MIN_VALUE) ? -1 : 1; } // Use binary search,一下省略若干代码 ..... return (int) (((lw >>> n) & 0xFFL) - ((rw >>> n) & 0xFFL)); } } // The epilogue to cover the last (minLength % 8) elements. for (int i = minWords * Longs.BYTES; i < minLength; i++) { int result = UnsignedBytes.compare(buffer1[offset1 + i], buffer2[offset2 + i]); if (result != 0) { return result; } } return length1 - length2; }
实现比原来复杂了一些。但这次一次可以比较8个字节了。这种getLong函数和系统的字节序是紧紧相关的,如果是小端序操作起来有点麻烦,代码先省略掉。这样操作实际效果如何?我们需要对比测试下。对比两个1M的字节数组,如果使用第一个版本,每次比较平均需要2.5499ms,如果使用第二个版本,需要0.8359ms,提升了3倍。对应这种CPU密集型的操作,这样的提升可是很可观的。
如果要提升性能,使用Unsafe直接访问内存也是不错的选择。
相关推荐
Java字节数组与常见类型转换工具,包括byte[] 与int long double float string boolean 等类型的相互转换。
易语言字节集与字节数组快速互转源码,字节集与字节数组快速互转,字节集到字节型数组,字节型数组到字节集,字节集到字节型数组_,复制内存_字节集
自定义byte数组,可变长度,轻量高效,解决集合存储简单数据的包装问题,自增缓存减少运算,方便多次调用,非线程同步
使用链式编程写法实现Java中byte数组的拼接。例如byte[] bytes = ByteUtils.get().add(0x41).add(07).add(11).add("15288930000").add(0x45).toArray();更灵活用法请参考Mybytes
但是为了使后台接收上传文件的方法既使用网页上传,又适应桌面应用程序上传,方法的参数设置成两个,一个为字符串类型,接收文件名,另一个为字节数组类型,用于接收文件内容。对于桌面应用,把文件内容读取到字节...
JAVA二进制字节数组字符十六进制BCD编码转换
易语言字节集与字节数组交换源码,字节集与字节数组交换,快速法_交换字节集与字节型数组,开始测试,结束测试,输出,结束并输出,取启动时间_,NtQuerySystemInformation
易语言源码易语言字节集与字节数组快速互转源码.rar
NULL 博文链接:https://zixiaolan.iteye.com/blog/452192
char short int long float double 转换成byte数组
易语言字节集转换到字节型数组源码,字节集转换到字节型数组,字节集到字节型数组_
LabVIEW程序,功能:将4字节的unsigned char输入组合成1个32-bit int值,若输入字节数不等于4则报错。
介绍php字符串与byte字节数组转化类,转换一个String字符串为byte数组,将字节数组转化为String类型的数据,转换一个int为byte数组,从字节数组中指定的位置读取一个Integer类型的数据,转换一个shor字符串为byte...
C#中的三种字节数组拼接方式的性能对比测试DEMO。 博文地址:http://blog.csdn.net/sqqyq/article/details/50986977
易语言整数到字节数组源码,整数到字节数组,十到十六,到十六进制文本
字符串转化为16进制的数组,字节数组如何转化为字符串
labview,ASCII码字符串与字节数组的互转,十六进制,例如:字符串BA34转字节数组结果为BA,34
C#字节数组转16进制字符串 C#字节数组转16进制字符串 QQ:292258449
易语言数组转指针源码,数组转指针,子程序1,子程序2,子程序3,数组_整数转指针,数组_指针转整数,数组_文本转指针,数组_指针转文本,数组_字节集转指针,数组_指针转字节集,内存_申请,内存_释放,内存_取长度,内存_写入,...