Fab*_*zio 91 php performance micro-optimization
这个问题仅供我使用,因为我总是喜欢编写优化的代码,这些代码也可以在便宜的慢速服务器(或具有大量流量的服务器)上运行
我环顾四周,无法找到答案.我想知道这两个例子之间的速度有多快,记住我的情况下数组的键并不重要(伪代码自然):
<?php
$a = array();
while($new_val = 'get over 100k email addresses already lowercased'){
if(!in_array($new_val, $a){
$a[] = $new_val;
//do other stuff
}
}
?>
<?php
$a = array();
while($new_val = 'get over 100k email addresses already lowercased'){
if(!isset($a[$new_val]){
$a[$new_val] = true;
//do other stuff
}
}
?>
Run Code Online (Sandbox Code Playgroud)
由于问题的关键不在于数组冲突,我想补充一点,如果你害怕碰撞插入$a[$new_value],你可以使用$a[md5($new_value)].它仍然可能导致冲突,但是当从用户提供的文件中读取时会从可能的DoS攻击中消失(http://nikic.github.com/2011/12/28/Supercolliding-a-PHP-array.html)
Dav*_*ess 112
到目前为止,答案是现场的.isset在这种情况下使用更快,因为
in_array必须检查每个值,直到找到匹配为止.in_array内置函数的开销更少.这些可以通过使用具有值的数组(在下面的测试中为10,000)来证明,迫使in_array进行更多搜索.
isset: 0.009623
in_array: 1.738441
Run Code Online (Sandbox Code Playgroud)
这是基于Jason的基准,通过填写一些随机值并偶尔找到数组中存在的值.所有随机,所以要注意时间会波动.
$a = array();
for ($i = 0; $i < 10000; ++$i) {
$v = rand(1, 1000000);
$a[$v] = $v;
}
echo "Size: ", count($a), PHP_EOL;
$start = microtime( true );
for ($i = 0; $i < 10000; ++$i) {
isset($a[rand(1, 1000000)]);
}
$total_time = microtime( true ) - $start;
echo "Total time: ", number_format($total_time, 6), PHP_EOL;
$start = microtime( true );
for ($i = 0; $i < 10000; ++$i) {
in_array(rand(1, 1000000), $a);
}
$total_time = microtime( true ) - $start;
echo "Total time: ", number_format($total_time, 6), PHP_EOL;
Run Code Online (Sandbox Code Playgroud)
Jas*_*ary 39
哪个更快:
isset()vsin_array()
isset() 是比较快的.
虽然很明显,但isset()只测试一个值.然而,in_array()将迭代整个数组,测试每个元素的值.
粗略的基准测试很容易使用microtime().
Total time isset(): 0.002857
Total time in_array(): 0.017103
Run Code Online (Sandbox Code Playgroud)
注意:无论是否存在,结果都是相似的.
<?php
$a = array();
$start = microtime( true );
for ($i = 0; $i < 10000; ++$i) {
isset($a['key']);
}
$total_time = microtime( true ) - $start;
echo "Total time: ", number_format($total_time, 6), PHP_EOL;
$start = microtime( true );
for ($i = 0; $i < 10000; ++$i) {
in_array('key', $a);
}
$total_time = microtime( true ) - $start;
echo "Total time: ", number_format($total_time, 6), PHP_EOL;
exit;
Run Code Online (Sandbox Code Playgroud)
我鼓励你也看看:
Ja͢*_*͢ck 18
使用isset()利用更快速的查找,因为它使用哈希表,避免了O(n)搜索的需要.
首先使用djb哈希函数对密钥进行哈希处理,以确定类似哈希密钥的桶O(1).然后迭代地搜索桶,直到找到确切的密钥O(n).
除非有任何故意的哈希冲突,否则这种方法可以产生更好的性能in_array().
请注意,isset()以您显示的方式使用时,将最终值传递给另一个函数需要使用array_keys()创建新数组.可以通过将数据存储在键和值中来实现存储器折衷.
更新
查看代码设计决策如何影响运行时性能的好方法,您可以查看脚本的编译版本:
echo isset($arr[123])
compiled vars: !0 = $arr
line # * op fetch ext return operands
-----------------------------------------------------------------------------
1 0 > ZEND_ISSET_ISEMPTY_DIM_OBJ 2000000 ~0 !0, 123
1 ECHO ~0
2 > RETURN null
Run Code Online (Sandbox Code Playgroud)
echo in_array(123, $arr)
compiled vars: !0 = $arr
line # * op fetch ext return operands
-----------------------------------------------------------------------------
1 0 > SEND_VAL 123
1 SEND_VAR !0
2 DO_FCALL 2 $0 'in_array'
3 ECHO $0
4 > RETURN null
Run Code Online (Sandbox Code Playgroud)
不仅in_array()使用相对低效的O(n)搜索,还需要将其作为函数(DO_FCALL)调用,而为此isset()使用单个操作码(ZEND_ISSET_ISEMPTY_DIM_OBJ).