为了账号安全,请及时绑定邮箱和手机立即绑定

什么更快:in_array或isset?

/ 猿问

什么更快:in_array或isset?

尚方宝剑之说 2019-11-14 09:44:35

这个问题对我来说只是个问题,因为我一直喜欢编写优化的代码,这些代码也可以在廉价的慢速服务器(或具有大量流量的服务器)上运行


我环顾四周,却找不到答案。我想知道在这两个示例之间有什么更快的方法,请记住在我的情况下数组的键并不重要(自然是伪代码):


<?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)]。它仍然可能导致冲突,但是当从用户提供的文件中读取时,它可以避免可能的DoS攻击(http://nikic.github.com/2011/12/28/Supercolliding-a-PHP-array.html)


查看完整描述

3 回答

?
智慧大石

到目前为止,答案是确定的。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;


查看完整回答
反对 回复 2019-11-14
?
慕运维8079593

哪个更快:isset()vsin_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;


查看完整回答
反对 回复 2019-11-14
?
慕婉清6462132

使用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

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)。


查看完整回答
反对 回复 2019-11-14

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信