为什么in_array整数严格模式比非严格模式慢?

时间:2019-07-03 12:49:00

标签: php php-internals

我一直认为in_array严格模式会比非严格模式更快或更慢。但是在进行一些基准测试后,我发现在搜索整数时,它们之间的执行时间存在巨大差异。字符串和数组测试表明严格模式更快。为什么?

  

测试代码-(PHP 7.2.1):

<?php

$array = array_fill(0, 10000, 12345);

for ($i=0; $i<100000; $i++) {
    in_array($i, $array, true);
}

  

时间php test.php

     

php -c test.php 12.98s用户0.04s系统98%cpu 13.234总


<?php

$array = array_fill(0, 10000, 12345);

for ($i=0; $i<100000; $i++) {
    in_array($i, $array, false);
}

  

时间php test.php

     

php -c test.php 6.44s用户0.04s系统99%cpu 6.522总计

2 个答案:

答案 0 :(得分:4)

通过对in_array的C源代码进行跟踪,我可以提供一些小见识。

事实证明,比较整数时,达到非严格模式的实际相等性检查的路径比严格模式要少。

严格模式

如果strict的{​​{1}}标志为true,则会发生以下情况:

  1. We call fast_is_identical_function for each element in the array

  2. fast_is_identical_function首先 测试每个操作数的类型是否不同(in_array),以期能够尽早返回Z_TYPE_P(op1) != Z_TYPE_P(op2);这是比较#1

  3. 如果类型相同(以您的测试用例为准),则我们测试false;我不知道这是做什么的,但这是比较#2

  4. 在两次比较后得出我们的第一个函数调用(Z_TYPE_P(op1) <= IS_TRUEwe jump into zend_is_identical

  5. zend_is_identical首先通过 测试Z_TYPE_P(op1) != Z_TYPE_P(op2)开始,这是另一种尽早失败的尝试。这是比较#3

  6. 如果类型相同,我们可以通过false语句比较#4

  7. 最后我们到达比较Z_LVAL_P(op1) == Z_LVAL_P(op2),该比较实际上测试了两个值比较#5 的相等性。

总共,要测试数组的每个元素是否等于我们要搜索的值,有5个比较和1个函数调用。

非严格模式

通过比较,专门用于整数(真的switch (Z_TYPE_P(op1)) s)的非严格流要简单得多,如下所示:

  1. 代替数组中的每个元素的LONGwe instead use fast_equal_check_function

  2. 方法fast_equal_check_function开始了一个比较复杂的过程,该过程将两个值与各种类型转换逻辑进行比较。但是,它的 first 测试确实针对整数进行了优化,如下所示:

    fast_is_identical_function

    我们可以看到它...

    1. 立即测试if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) { if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) { return Z_LVAL_P(op1) == Z_LVAL_P(op2); 的类型是否为op1,然后
    2. 立即测试LONG的类型是否为op2,然后
    3. 立即返回LONG的结果

对于非严格情况,总共有3个简单相等比较和0个函数调用,而对于严格情况,至少有 5个比较和1个跳转。

在这种情况下,尝试进行早期优化会使严格检查变得更慢(通过反复测试操作数的类型,希望我们能够更快找到不等式),而不是特定的非严格情况比较两个整数。

答案 1 :(得分:1)

似乎与针和/或干草堆中的元素类型有关,请注意:

来自http://sandbox.onlinephpfunctions.com/的PHP 7.3.5

$iterations = 10000000;
$needle = false;
$haystack = [ true ];

$start = microtime( true );
for( $i = 0; $i < $iterations; ++$i )
{
    in_array( $needle, $haystack, true );
}
echo ( microtime( true ) - $start ).' strict'.PHP_EOL;

$start = microtime( true );
for( $i = 0; $i < $iterations; ++$i )
{
    in_array( $needle, $haystack, false );
}
echo ( microtime( true ) - $start ).' not strict';

产生:

0.29996585845947 strict
0.40397191047668 not strict

但是如果我们使用:

$needle = 1;
$haystack = [ 2 ];

然后我们得到:

0.34480714797974 strict
0.28275084495544 not strict

但是,PHP 5.6.29产生的差异可以忽略不计,并且多次运行相同的测试可以使严格严格于非严格,反之亦然。