В чем разница между использованием mt_rand($min, $max)
и rand($min, $max)
относительно скорости?
Разница между mt_rand() и rand()
Ответ 1
Update
Так как PHP 7.1 mt_rand
полностью заменил rand
, а rand
сделал псевдоним для mt_rand
. В ответе ниже рассматриваются различия между двумя функциями для более старых версий и причины введения mt_rand
.
Скорость не была вызвана mt_rand
!
Функция rand
существовала раньше, чем mt_rand
, но она была глубоко ошибочной. PRNG должен получить некоторую энтропию, число, из которого оно генерирует последовательность случайных чисел. Если вы распечатаете список из десяти чисел, которые были сгенерированы с помощью rand()
следующим образом:
for ($i=0;$i<10;++$i)
echo rand(), PHP_EOL;
Вывод может использоваться для определения того, что было за семенем rand
, и с его помощью вы можете предсказать следующие случайные числа. Есть инструменты, которые делают это, поэтому google немного и протестируйте его.
Также существует проблема с rand
релятививно быстро отображать шаблоны в своих случайных числах как показано здесь. Проблема mt_rand
, похоже, тоже намного лучше.
mt_rand
использует лучший алгоритм рандомизации (Mersenne Twist), который требует большего количества случайных чисел до того, как семя может быть определено и быстрее. Это не означает, что mt_rand
по определению быстрее, чем rand
, это означает, что способ генерации чисел быстрее и, по-видимому, не оказывает реального влияния на функцию как показали другие ответы здесь.
В любом случае, посмотрите mt_srand
и srand
документы. Я уверен, что они будут содержать дополнительную информацию
Если алгоритм mt_rand
преобразуется в увеличение производительности, то это здорово для вас, но это счастливое совпадение. TL; ТР:
mt_rand
был введен для устранения проблем, существующих в rand
!
Ответ 2
Обновление (PHP 7.1):
rand()
иsrand()
теперь были добавлены псевдонимы кmt_rand()
иmt_srand()
соответственно. Это означает, что выход для следующих функций имеет следующие изменения:rand()
,shuffle()
,str_shuffle()
иarray_rand()
.
Это означает, что с версии 7.1 нет практической разницы между обоими из них, потому что rand
вызывает mt_rand
внутренне.
До PHP 7.1:
Использование rand()
не является плохой практикой, если оно не используется для целей безопасности, я обычно использую rand()
(привычка?).
Если вам нужно огромное количество случайных чисел, вам понадобится mt_rand
вместо rand
. mt_rand
имеет период 2 19937 - 1, намного лучше, чем rand
(2 32). Взгляните на в этой статье о создании графического шаблона с использованием rand
и mt_rand
.
periodicity и entropy являются единственными причинами использования mt_rand()
вместо rand()
, а не улучшения безопасности или скорости.
Математически mt_rand
имеет больше entropy и более высокий periodicity, чем rand
(2 19937 -1 против 2 32).
Если вам нужны несколько случайных чисел, и безопасность не проблема, rand
выполнит задание (получите случайное число, чтобы решить, как запустить процесс очистки).
Улучшения скорости тестирования
На практике нет большой разницы в скорости между двумя функциями (возможно, потому, что накладные расходы на PHP⇔C?).
PHP-код:
<?php
for ($c = 0; $c < 3; $c++) {
$start = microtime(true);
$sum = 0.0;
for ($i = 0; $i < 100000000; $i++) {
$sum += rand();
}
printf('[rand %d] Time: %.3f s%s', $c, microtime(true) - $start, PHP_EOL);
}
for ($c = 0; $c < 3; $c++) {
$start = microtime(true);
$sum = 0.0;
for ($i = 0; $i < 100000000; $i++) {
$sum += mt_rand();
}
printf('[mt_rand %d] Time: %.3f s%s', $c, microtime(true) - $start, PHP_EOL);
}
Тесты в PHP 7.0.19:
$ php timing.php
[rand 0] Time: 4.658 s
[rand 1] Time: 4.664 s
[rand 2] Time: 4.654 s
[mt_rand 0] Time: 4.267 s
[mt_rand 1] Time: 4.255 s
[mt_rand 2] Time: 4.261 s
Тесты в PHP 5.4.45 (медленная машина):
$ php timing.php
[rand 0] Time: 10.862 s
[rand 1] Time: 10.889 s
[rand 2] Time: 10.615 s
[mt_rand 0] Time: 10.948 s
[mt_rand 1] Time: 9.883 s
[mt_rand 2] Time: 10.190 s
Только 6-9%, а не 400%, как утверждается.
Использование для целей безопасности
Но если вашему приложению нужно много энтропии, потому что проблемы с безопасностью, вам понадобится более безопасный способ и openssl_random_pseudo_bytes()
, возможно, лучшее решение, делает его работу (гораздо лучше, но медленнее - нам нужна безопасность по скорости?) полагаясь на связанные с openssl проблемы.
Ни rand()
и mt_rand()
достаточно безопасны:
Предостережение Эта функция не генерирует криптографически безопасную значения и не должны использоваться для криптографических целей. Если тебе надо криптографически безопасное значение, рассмотрите возможность использования
random_int()
,random_bytes()
илиopenssl_random_pseudo_bytes()
.
Существуют расширения PHP, такие как random_compat
, но я не рекомендовал их использовать, если это не нужно.
Ответ 3
Руководство по PHP на mt_rand()
утверждает, что оно:
который будет генерировать случайные числа в четыре раза быстрее, чем обеспечивает средний libc rand().
Ответ 4
Как и в случае с PHP 7.1, нет разницы вообще. rand() теперь является псевдонимом для mt_rand().
См. http://php.net/manual/en/migration71.incompatible.php#migration71.incompatible.rand-srand-aliases
И более подробная информация: https://wiki.php.net/rfc/rng_fixes
Ответ 5
Ниже приведена разница в скорости для обоих из них: - mt_rand($min, $max)
четыре раза быстрее по сравнению с rand($min, $max)
Причина в том, что rand($min, $max)
использует генератор случайных чисел libc, а mt_rand($min, $max)
использует Mersenne Twister, что в четыре раза быстрее.
Надеюсь, что это решит ваши сомнения.
Спасибо.
Ответ 6
Они кажутся равными по скорости:
function timeit($times, $func) {
$t = microtime(1);
while($times--) $func();
return microtime(1) - $t;
}
echo PHP_OS, " ", phpversion(), "\n";
echo timeit(100000, function() { rand(0,1000); }), "\n";
echo timeit(100000, function() { mt_rand(0,1000); }), "\n";
Результаты для OSX Mavericks и VirtualBox'ed Ubuntu 11:
Darwin 5.5.19
0.038038969039917
0.033117055892944
Linux 5.3.6-13ubuntu3.10
0.031459093093872
0.031935214996338
Если эти меры верны, комментарий к руководству, упомянутый в другом месте, должен считаться неправильным/устаревшим.