什么更快: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() vs in_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它,将查看每个数组元素)