我一直认为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
通过跟踪C的C源代码,我可以提供一些小见识in_array
。
It turns out, when comparing integers, the path to reach the actual equality check for non-strict mode involves fewer operations than strict mode.
In the case where the strict
flag to in_array
is true, the following occurs:
We call fast_is_identical_function
for each element in the array
The fast_is_identical_function
first
tests that the types of each operand are different (Z_TYPE_P(op1) != Z_TYPE_P(op2)
) in hopes of being able to return false
early; this is comparison #1.
If the types are the same (they are, in your test case), we then test (Z_TYPE_P(op1) <= IS_TRUE
; I've no idea what this does, but it's comparison #2.
After both comparisons have evaluated to false
, we jump into zend_is_identical
, our first function invocation.
zend_is_identical
starts out by again testing Z_TYPE_P(op1) != Z_TYPE_P(op2)
, another attempt to fail early. This is comparison #3.
If the types are the same, we can descend through the switch (Z_TYPE_P(op1))
statement, comparison #4
Finally we reach the comparison Z_LVAL_P(op1) == Z_LVAL_P(op2)
which actually tests the equality of the two values, comparison #5.
In total, to test whether each element of the array is equal to the value we're searching for, there are 5 comparisons and 1 function invocation.
By comparison, the non-strict flow for integers specifically (really LONG
s) is much simpler, as follows:
Instead of fast_is_identical_function
, we instead use fast_equal_check_function
for each element in the array.
该方法fast_equal_check_function
开始了将两个值与各种类型转换逻辑进行比较的更为复杂的过程。但是,它的第一个测试确实是针对整数进行了优化,如下所示:
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
是LONG
,它是,则op2
是LONG
,它是,则Z_LVAL_P(op1) == Z_LVAL_P(op2)
对于非严格情况,总共有3个简单相等比较和0个函数调用,而对于严格情况,则至少有 5个比较和1个跳转。
这似乎是一种情况,即尝试进行早期优化会使严格检查的速度比比较两个整数的特定非严格情况的速度慢(通过反复测试操作数的类型,希望我们能更快地找到不等式)。
因此,这可能是下一个PHP版本中进行优化的地方,对吗?
@tom我不认为这真的是一个问题。该代码已经进行了相当大的优化,您可能会冒险通过更改其他类型的输入而引入其他类型的性能问题。我认为最好将当前的严格表现视为正常,将非严格的long-long情况视为不错的奖励。
对。你是对的。我考虑过以非严格模式为代价专注于严格模式(如果需要提高严格模式的速度)
@tom已在github.com/php/php-src/commit/…中 “修复” :)