Ответ 1
Первое, хотя было почему не использовать простую функцию md5
?.
Попытка написать хэш самостоятельно
Одна из наиболее часто упоминаемая функция - это простая хэш-функция Bernstein, также обозначаемая как Times 33 with Addition
. Он используется в php
по zend для создания хэшей для ключей ассоциативного массива. В php
он может быть реализован следующим образом:
function djb2($s){
$word = str_split($s);
$length = count($word);
$hashAddress = 5381;
for ($counter = 0; $counter < $length; $counter++){
$hashAddress = (($hashAddress << 5) + $hashAddress) + $word[$counter];
}
return $hashAddress;
}
echo djb2("stackoverflow");
Проблема заключается в том, что когда она реализована таким образом, она довольно медленная. Тесты показывают, что он ~ 3 раза медленнее, чем md5
. Поэтому нам нужно найти самую быструю внутреннюю реализацию функции hash
.
Поиск лучшего внутреннего хэша
Просто возьмите все algos и измерьте время, чтобы хэшировать миллион строк.
function testing($algo, $str) {
$start = microtime(true);
for($ax = 0; $ax < 1000000; $ax++){
hash($algo, $str);
}
$end = microtime(true);
return ($end - $start);
}
$algos = hash_algos();
$times = [];
foreach($algos as $algo){
$times[$algo] = testing($algo, "stackoverflow");
}
// sort by time ASC
asort($times);
foreach($times as $algo => $time){
echo "$algo -> " . round($time, 2)."sec\n";
}
Мои результаты:
fnv1a32 -> 0.29sec
fnv132 -> 0.3sec
crc32b -> 0.3sec
adler32 -> 0.3sec
crc32 -> 0.31sec
joaat -> 0.31sec
fnv1a64 -> 0.31sec
fnv164 -> 0.31sec
md4 -> 0.46sec
md5 -> 0.54sec
...
md2 -> 6.32sec
Результат немного меняется от исполнения к исполнению - первые 8 альгос перетасовываются из-за их близких скоростей и зависимости от нагрузки на сервер.
Что следует выбрать?
Вы можете взять любую из вышеперечисленных функций выше: $hash = hash('crc32', $string);
. На самом деле широко используемая функция md5
в 1,7 раза медленнее лидеров.
Bonus
Существуют и другие функции, такие как SuperFastHash, которые не реализованы в коде php
, но они в 4 раза быстрее, чем crc32
.