Fast(er) comparison of longs in byte format?

2019-08-11 19:13发布

I have a key value store that has byte[] keys. Some of these keys will be used for longs (longs themselves, also Localdate and LocalTime instances).

I have a nice clean comparator, using standard Java and Guava:

    @Override
    public int compare(byte[] left, byte[] right) {
        long leftLong = Longs.fromByteArray(left);
        long rightLong = Longs.fromByteArray(right);
        return Long.compare(leftLong, rightLong);
    }

but it's slower than I would expect. Sorting 100,000 longs takes 100ms, whereas sorting 100,000 ints takes 6ms.

Is there a faster way to compare two longs, perhaps by avoiding the int conversion?

(You may be wondering if it really needs to be faster. If possible yes, as it will be called for every search, scan, insert, and delete of longs, dates, etc. into the store.)

2条回答
Viruses.
2楼-- · 2019-08-11 19:36

I am not surprised it takes long: allocating and destroying an order of a trillion small objects seems taxing. Why not just compare arrays themselves?

public int compare(byte[] left, byte[] right) {
    int cmp = 0;
    for(int i = 0; i < 8 && cmp == 0; i++) { 
       cmp = (i == 0 || (left[i] >= 0 == right[i] >= 0)) ? left[i] - right[i] : right[i] - left[i]           
    }
    return cmp;
}
查看更多
ら.Afraid
3楼-- · 2019-08-11 19:42

This is another variation. It is similar to the original, but effectively does the two byte to long transformations in a single loop. This improves performance about ~20%-30%. @Dima's version is faster.

    public static int compareLongs(byte[] left, byte[] right) {
        long leftLong = 0;
        long rightLong = 0;
        for (int i = 0; i < 8; i++) {
            leftLong <<= 8;
            rightLong <<= 8;
            leftLong |= (left[i] & 0xFF);
            rightLong|= (right[i] & 0xFF);
        }
        return Long.compare(leftLong, rightLong);
    }
查看更多
登录 后发表回答