Я хочу использовать байтовый массив в качестве ключа поиска в concurentDictionary
. В настоящее время я решаю это, используя пользовательский EqualityComparer<byte[]>
.Использование байтового массива в качестве словарного ключа
Это прекрасно работает, но я понимаю, что генератор hashcode генерирует много перекрытий, когда вещи оказываются в одном и том же хэш-ведре.
public class ByteArrayEqualityComparer : EqualityComparer<byte[]>
{
public override bool Equals(byte[] x, byte[] y)
{
//fast buffer compare
return UnsafeCompare(x, y);
}
public override int GetHashCode(byte[] obj)
{
int hash = 0;
for (int i = 0; i < obj.Length; i += 2)
{
hash += obj[i]; //xor? shift? black magic?
}
return hash;
}
}
Что было бы хорошей формулой для создания относительно быстрого хеша из массива байтов?
Моя идея состоит в том, что я могу вычислить хэш-код, пропустив каждый x байтов для скорости. Поскольку окончательное сравнение все еще выполняется по полному набору данных, кажется бессмысленным сравнивать все байты несколько раз.
Я предполагаю, что некоторая магия xor и смещение на хэш-var сделают все лучше.
Это чрезвычайно критичная производительность, поэтому любой ярлык, который можно использовать, тоже приветствуется.
В результате я решил использовать это решение. Я использую struct, чтобы обернуть массив байтов, чтобы я мог использовать кешированный хэш-код для него вместо вычисления его для каждого сравнения. Это привело к очень хорошему усилению производительности.
public struct ByteArrayKey
{
public readonly byte[] Bytes;
private readonly int _hashCode;
public override bool Equals(object obj)
{
var other = (ByteArrayKey) obj;
return Compare(Bytes, other.Bytes);
}
public override int GetHashCode()
{
return _hashCode;
}
private static int GetHashCode([NotNull] byte[] bytes)
{
unchecked
{
var hash = 17;
for (var i = 0; i < bytes.Length; i++)
{
hash = hash*23 + bytes[i];
}
return hash;
}
}
public ByteArrayKey(byte[] bytes)
{
Bytes = bytes;
_hashCode = GetHashCode(bytes);
}
public static ByteArrayKey Create(byte[] bytes)
{
return new ByteArrayKey(bytes);
}
public static unsafe bool Compare(byte[] a1, byte[] a2)
{
if (a1 == null || a2 == null || a1.Length != a2.Length)
return false;
fixed (byte* p1 = a1, p2 = a2)
{
byte* x1 = p1, x2 = p2;
var l = a1.Length;
for (var i = 0; i < l/8; i++, x1 += 8, x2 += 8)
if (*(long*) x1 != *(long*) x2) return false;
if ((l & 4) != 0)
{
if (*(int*) x1 != *(int*) x2) return false;
x1 += 4;
x2 += 4;
}
if ((l & 2) != 0)
{
if (*(short*) x1 != *(short*) x2) return false;
x1 += 2;
x2 += 2;
}
if ((l & 1) != 0) if (*x1 != *x2) return false;
return true;
}
}
}
Стандартная модель, например. [Здесь] (http://stackoverflow.com/a/263416/215380). Если это полезно для вас, я закрою этот вопрос как дубликат. – Rawling
, что кажется именно то, что мне нужно, спасибо! –
Я действительно не вижу, как это дубликат, так как мясо вопроса связано с сравнениями байтовых массивов – Oliver