什么是更快:in_array或isset?

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在这种情况下使用更快,因为

  • 它对密钥使用O(1)哈希搜索,但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)

  • @Fabrizio - 可以复制数组值并包含不可清除的对象.键必须是唯一的,并且只能是字符串和整数,这使它们易于清理.虽然您可以创建一个一对一的映射来同时隐藏键和值,但这不是PHP数组的工作方式. (3认同)
  • 如果您确定数组包含唯一值,则还有另一个选项-* flip + isset *。 (2认同)

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


Mik*_*ant 7

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