什么是更快:in_array或isset?

时间:2012-11-20 22:20:35

标签: 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
    }
}
?>

由于问题的重点不是数组冲突,我想补充一点,如果你害怕$a[$new_value]的碰撞插入,你可以使用$a[md5($new_value)]。它仍然可能导致冲突,但在从用户提供的文件(http://nikic.github.com/2011/12/28/Supercolliding-a-PHP-array.html

中读取时会从可能的DoS攻击中消失

4 个答案:

答案 0 :(得分:106)

到目前为止,答案是现实的。在这种情况下使用isset会更快,因为

  • 它对密钥使用O(1)哈希搜索,而in_array必须检查每个值,直到找到匹配为止。
  • 作为操作码,它比调用in_array内置函数的开销更小。

这些可以通过使用带有值的数组(在下面的测试中为10,000)来证明,迫使in_array进行更多搜索。

isset:    0.009623
in_array: 1.738441

这建立在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;

答案 1 :(得分:38)

  

哪个更快:isset() vs in_array()

isset()更快。

虽然很明显,isset()只测试一个值。而in_array()将迭代整个数组,测试每个元素的值。

使用microtime()进行粗略的基准测试非常简单。

结果:

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;

其他资源

我鼓励你也看看:

答案 2 :(得分:17)

使用isset()可以利用更快的查询速度,因为它使用hash table,无需进行O(n)次搜索。

首先使用djb hash function对密钥进行哈希处理,以确定O(1)中类似哈希密钥的存储桶。然后迭代搜索存储桶,直到在O(n)中找到确切的密钥。

除了in_array()之外,这种方法的效果要比isset()好得多。

请注意,以您显示的方式使用array_keys()时,将最终值传递给另一个函数需要使用echo isset($arr[123])来创建新数组。通过将数据存储在键和值中,可以实现内存泄露。

<强>更新

了解代码设计决策如何影响运行时性能的好方法,您可以查看脚本的intentional hash collisions

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)不仅使用相对低效的DO_FCALL搜索,还需要将其作为函数调用(isset()),而ZEND_ISSET_ISEMPTY_DIM_OBJ使用单个操作码({ {1}})为此。

答案 3 :(得分:6)

第二个会更快,因为它只查找特定的数组键,并且不需要遍历整个数组,直到找到它(如果找不到,将查看每个数组元素)