什么更快:in_array或isset?
这个问题仅仅是为了我,因为我总是喜欢写优化的代码,也可以运行廉价的慢服务器(或具有很多stream量的服务器)
我环顾四周,无法find答案。 我想知道这两个例子之间有什么更快的记住,在我的情况下数组的键不重要(自然伪代码):
<?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 } } ?>
由于问题的关键不是数组冲突,我想补充一点,如果你害怕碰撞insert $a[$new_value]
,你可以使用$a[md5($new_value)]
。 它仍然可能导致冲突,但是从用户提供的文件中读取时可能会遭受DoS攻击( http://nikic.github.com/2011/12/28/Supercolliding-a-PHP-array.html )
到目前为止的答案是点亮的。 在这种情况下使用isset
更快,因为
- 它在键上使用O(1)哈希search,而
in_array
必须检查每个值直到find匹配。 - 作为一个操作码,它比调用
in_array
内置函数的开销less。
这些可以通过使用具有值的数组(在下面的testing中为10,000)来演示,迫使in_array
进行更多的search。
isset: 0.009623 in_array: 1.738441
这build立在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;
哪个更快:
isset()
vsin_array()
isset()
更快。
虽然它应该是显而易见的, isset()
只testing一个值。 而in_array()
将迭代整个数组,testing每个元素的值。
使用microtime()
粗略的基准testing是相当容易的。
结果:
Total time isset(): 0.002857 Total time in_array(): 0.017103
注:无论是否存在,结果都是相似的。
码:
<?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;
其他资源
我鼓励你也看看:
- PHP基准
- PHPPerf
- 的XDebug
使用isset()
利用更快速的查找,因为它使用了一个哈希表 ,避免了O(n)
search的需要。
首先使用djb散列函数对密钥进行散列,以确定O(1)
的类似散列密钥的桶。 然后迭代search桶,直到在O(n)
find确切的键。
除了任何有意的散列冲突 ,这种方法比in_array()
产生更好的性能。
请注意,按照您所示的方式使用isset()
时,将最终值传递给另一个函数需要使用array_keys()
来创build一个新数组。 可以通过将数据存储在键和值中来实现内存泄漏。
更新
查看代码devise决策如何影响运行时性能的好方法,可以查看脚本的编译版本 :
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
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
in_array()
不仅使用相对低效的O(n)
search,还需要将其作为函数( DO_FCALL
)进行调用,而isset()
使用单个操作码( ZEND_ISSET_ISEMPTY_DIM_OBJ
)。
第二个会更快,因为它只查找特定的数组键,不需要遍历整个数组,直到find(如果没有find它,将查看每个数组元素)
- 用Java创build一个简单的HTTP服务器?
- Xcode 6.0.1命令/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc失败,退出代码1