php 什么更快:in_array还是isset?[已关闭]

8ulbf1ek  于 2022-12-28  发布在  PHP
关注(0)|答案(4)|浏览(141)

就目前的情况而言,此问题不适合我们的问答格式。我们希望答案能得到事实、参考资料或专业知识的支持,但此问题可能会引发辩论、争论、民意调查或广泛讨论。如果您认为此问题可以改进并可能重新讨论,请访问visit the help center以获取指导。
10年前关闭了。
这个问题只是对我来说,因为我总是喜欢写优化的代码,也可以运行在廉价缓慢的服务器(或服务器与大量的流量)
我环顾四周,没有找到答案,我想知道这两个例子中哪一个更快,记住数组的键在我的例子中并不重要(当然是伪代码):

<?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攻击

jtw3ybtb

jtw3ybtb1#

到目前为止,答案都是正确的。在这种情况下使用isset更快,因为

  • 它对键使用O(1)散列搜索,而in_array必须检查每个值,直到找到匹配。
  • 作为一个操作码,它的开销比调用in_array内置函数要小。

这可以通过使用一个值为10,000的数组(在下面的测试中为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;
0s7z1bwu

0s7z1bwu2#

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

其他资源

我鼓励你也看看:

b4lqfgs4

b4lqfgs43#

使用isset()可以利用更快的查找速度,因为它使用hash table,避免了O(n)搜索。
首先使用djb hash function对密钥进行散列,以确定O(1)中经过类似散列的密钥桶,然后迭代搜索该桶,直到在O(n)中找到准确的密钥。
除了intentional hash collisions之外,这种方法产生的性能远远优于in_array()
请注意,当以您所展示的方式使用isset()时,将最终值传递给另一个函数需要使用array_keys()创建一个新数组。将数据同时存储在键和值中可能会导致内存损失。

    • 更新**

查看代码设计决策如何影响运行时性能的一个好方法是查看脚本的compiled version

  • 一米七三 *
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
  • 一米八分一秒 *
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)。

i2byvkas

i2byvkas4#

第二种方法会更快,因为它只查找特定的数组键,不需要迭代整个数组直到找到它(如果没有找到,将查看每个数组元素)

相关问题