【问题标题】:what is faster: in_array or isset? [closed]什么更快:in_array 或 isset? [关闭]
【发布时间】:2026-01-04 02:50:01
【问题描述】:

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

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

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

【问题讨论】:

  • 如果您一直在努力编写优化的代码,那么您肯定会偶尔使用分析器吗?
  • 我投票决定重新开放。问题的形式很好,答案有事实和参考资料支持。虽然是微观优化,但这些类型的问题是建设性的
  • @JasonMcCreary 第二;还有一个。
  • 这是多年后的事了,但我什至不认为这是一个微优化。对于大型数据集,它可以产生很大的不同!
  • ...这个问题对我来说看起来“很有建设性”。我将开始另一个重新开放的活动。

标签: php performance micro-optimization


【解决方案1】:

到目前为止的答案都是准确的。在这种情况下使用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;

【讨论】:

  • 我知道哈希,但想知道为什么在可能的情况下不对数组值执行类似的操作来加速函数,如果使用类似的值,只需在值..正确吗?
  • @Fabrizio - 数组值可以重复并包含不可散列的对象。键必须是唯一的,并且只能是字符串和整数,这使得它们易于散列。虽然您可以创建一个对键和值进行哈希处理的一对一映射,但这不是 PHP 数组的工作方式。
  • 如果您确定数组包含唯一值,那么还有另一个选项 - flip + isset
  • 值得注意的是,在这个例子中,翻转的 isset 仍然比 in_array 快:`` $start = microtime(true); $foo = array_flip($a); for ($i = 0; $i
  • @AndreBaumeier 哪个更快取决于数组的大小以及您将进行多少次测试。翻转一万个元素的数组来执行三个测试可能效率不高。
【解决方案2】:

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

其他资源

我建议你也看看:

【讨论】:

  • 不错的解决方案。我很惊讶越来越多的人不会更多地使用microtime() 或其他工具来分时他们的功能/代码。非常有价值。
  • 在空数组中搜索相同的键只会突出调用 in_array 函数与使用 isset 内置函数的开销。使用包含一堆随机键并偶尔搜索现有键/值的数组会更好。
  • 我确实经常使用基准测试和微时间,但我也意识到,在测试whileforeach 时,每次刷新我都会获得不同的“赢家”。它总是依赖于太多的服务器变量,最好的方法是在不同的时间迭代非常多的次数并获得更经常获胜的那个,或者只知道后台发生的事情并知道它将是最终的赢家无论如何
  • @David Harkness,你已经挑剔了我的答案。如果您想要更多,请站在我的肩膀上并发布您自己的答案。 :) 尽管如此,如果函数开销相对于isset() 已经显着增加,是什么让你认为传递一个 更大的 数组会使它更快
  • @Fabrizio - 阅读hashing functionshash tables
【解决方案3】:

使用isset() 可以加快查找速度,因为它使用hash table,避免了O(n) 搜索的需要。

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

除非有任何intentional hash collisions,否则这种方法的性能要比in_array() 好得多。

请注意,当以您展示的方式使用isset() 时,将最终值传递给另一个函数需要使用array_keys() 创建一个新数组。可以通过将数据存储在键和值中来进行内存折衷。

更新

查看代码设计决策如何影响运行时性能的好方法,您可以查看脚本的compiled version

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

【讨论】:

    【解决方案4】:

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

    【讨论】:

    • 但也取决于全局范围内搜索到的变量的下落
    • @EL2002,你能详细说明一下那个声明吗?
    • Mike,如果没有找到isset(),即使它也不会查看整个数组?
    • @Fabrizio 不,它不需要迭代。在内部(在 C 中)PHP 数组只是一个哈希表。为了查找单个索引值,C 只需对该值进行散列并在内存中查找其分配的位置。要么有值,要么没有。
    • @Fabrizio 这篇文章很好地概述了数组是如何通过 PHP 在 C 中内部表示的。 nikic.github.com/2012/03/28/…
    最近更新 更多