【发布时间】:2015-04-29 21:42:03
【问题描述】:
使用mt_rand($min, $max)和rand($min, $max)在速度上有什么区别?
【问题讨论】:
标签: php performance optimization random
使用mt_rand($min, $max)和rand($min, $max)在速度上有什么区别?
【问题讨论】:
标签: php performance optimization random
mt_rand() 上的 PHP 手册指出:
生成随机数的速度比 libc rand() 提供的平均速度快四倍。
【讨论】:
rand() 是在 PHP 中使用了很长时间的标准语言结构(可能从 C 语言移植而来)。据我所知,mt_rand() 有点新。这就是为什么 mt_rand() 被手册称为 better rand :)
rand 的问题,而 mt_rand => 例如,可以从输出中轻松推断出种子
mt_rand函数说的快,是它使用的算法比平均 libc rand 函数。这并不意味着这种速度差异将转化为 PHP 的性能差异......它只是说明 PRNG 将更快地生成数字,仅此而已,仅此而已
以下是两者的速度差异:-mt_rand($min, $max) 比 rand($min, $max) 快 四 倍
原因是那,rand($min, $max) 使用 libc 随机数生成器,而 mt_rand($min, $max) 使用 Mersenne Twister,速度快了四倍。
希望它能解决您的疑问。
谢谢。
【讨论】:
rand 函数快四倍。这并不意味着mt_rand 比rand 快四倍。无论如何都不是。速度甚至不是两者之间最大的区别:看我的答案
mt_rand 比 rand 快 4 倍。它不是。这是一个错误的说法:生成数字的内部机制更快,但这并不意味着函数变得更快。乔治的回答很好地说明了这一点。
mt_rand(PHP 函数)比rand(PHP 函数)快。它只是不是。它生成数字的方式更快,但就您的 PHP 代码而言,它并没有快 4 倍。 而且你从来没有提到mt_rand的更好分布,这实际上是这里两个函数之间最大的区别
它们的速度似乎相等:
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 的 Ubuntu 11 的结果:
Darwin 5.5.19
0.038038969039917
0.033117055892944
Linux 5.3.6-13ubuntu3.10
0.031459093093872
0.031935214996338
如果这些措施是正确的,则其他地方提到的手动注释应被视为错误/过时。
【讨论】:
mt_rand 快四倍的说法是一个可怕的笼统说法,确实很可能已经过时了。 "average" libc rand 可能已经改变了一百次,因为这句话被添加到 PHP 文档中......此外,mt_rand 出于速度原因没有添加,它被添加了因为旧的rand PRNG 的固有缺陷。速度提升从来不是mt_rand 的主要原因,这似乎是每个人都忘记的。
mt_rand 的更好分布,只关注速度,但是,那是 OP 的问题。那个,以及一些用户的态度让我无所适从......不过我和你在一起,OP接受了更好的答案,所以我会留下这个
由于 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 种子是什么,并使用它,您可以预测下一个随机数。有一些工具可以做到这一点,所以谷歌一下并测试它。
rand 的随机数 as demonstrated here 相对快速地显示模式也存在问题。 mt_rand 的问题似乎也解决了很多。
mt_rand 使用更好的随机化算法 (Mersenne Twist),它需要在确定种子之前知道更多随机数并且更快。 这并不意味着根据定义,mt_rand 比 rand 快,这只意味着生成数字的方式更快,并且似乎正如此处的其他答案所证明的那样,对函数的性能没有真正的影响。
不管怎样,看看the mt_srand 和the srand docs。我相信它们会包含更多信息
如果mt_rand 的算法可以提高性能,那么这对您来说是件好事,但这是一个巧合。 TL;TR:
mt_rand 是为了解决rand 中存在的问题!【讨论】:
rand 成为别名之前。 WRT 内容:它的主要重点是解释 为什么 mt_rand 最初被引入(这仍然是相关的)。为了完整起见,我将添加一个更新,说明 rand 现在是别名。除此之外,提供的信息仍然是正确的 IMO
random_int() 和 random_bytes()。
rand()andsrand()have now been made aliases tomt_rand()andmt_srand(), respectively. 这意味着以下函数的输出发生了变化:rand()、shuffle()、str_shuffle()和array_rand()。
这意味着从 7.1 版开始,它们之间没有实际区别,因为rand calls mt_rand internally。
如果不用于安全目的,使用rand() 并不是一个坏习惯,我通常使用rand()(习惯?)。
如果您需要大量随机数,则需要mt_rand 而不是rand。 mt_rand 的周期为 219937 - 1,远远优于 rand (232)。看看this article,了解使用rand 和mt_rand 生成图形模式。
Periodicity 和 entropy 是使用 mt_rand() 而不是 rand() 的唯一原因,而不是提高安全性或速度。
从数学上讲,mt_rand 比 rand 有更多的entropy 和更大的periodicity(219937-1 与 232)。
如果您需要一些随机数并且安全性不成问题,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() 可能是最好的解决方案,它的工作是否有效(好得多但速度较慢?我们需要安全而不是速度?) relying on openssl related issues.
rand() nor mt_rand() 都不够安全:
注意此函数不会生成加密安全 值,不应用于加密目的。如果你需要 一个加密安全值,考虑使用
random_int(),random_bytes(),或openssl_random_pseudo_bytes()。
有像random_compat这样的PHP扩展,但如果没有必要,我不建议使用它们。
【讨论】:
从 PHP 7.1 开始,完全没有区别。 rand() 现在是 mt_rand() 的别名。
见http://php.net/manual/en/migration71.incompatible.php#migration71.incompatible.rand-srand-aliases
【讨论】: