性能改进:array_flip 函数的替代方案

Rac*_*hel 2 php performance

有什么办法可以避免使用 array_flip 来优化性能。我正在select从数据库中执行一条语句,准备查询并执行它,并将数据作为关联数组存储在数组中,$resultCollection然后将数组op中的每个元素$resultCollection存储outputId在其中,op[]如代码所示。

我已经解释了代码,所以我的问题是如何使用 array_flip 为 array_flip 实现类似的替代方案,因为我想提高性能。

$resultCollection = $statement->fetchAll(PDO::FETCH_ASSOC);

$op = array();

//Looping through result collection and storing unicaOfferId into op array. 
foreach ($resultCollection as $output)
{
$op[] = $output['outputId'];
}

//Here op array has key as 0, 1, 2...and value as id {which I am interested in}

//Flip op array to get offer ids as key

$op = array_flip($op);

//Doing a flip to get id as key. 

foreach ($ft as $Id => $Off)
{
    $ft[$Id]['is_set'] = isset($op[$Id]);
}
Run Code Online (Sandbox Code Playgroud)

MAC*_*rha 7

我添加此答案是因为您在标题“性能改进”中提到了。

TL; 博士

您应该继续使用array_flip(). 与foreach循环相比,在性能方面,它的处理速度要快得多,尤其是在大型数组上(可能是因为它的本机性质)。性能在小阵列中几乎可以忽略。然而,赢家是array_flip()。总是。

让我们测试

我测试的结果(PHP 7.4,Fedora 32 工作站):

Testing an array with 10 elements:
  Average time for array_flip(): 3.0E-5
  Average time for foreach: 7.0E-5
  How much array_flip() is faster: 105%

Testing an array with 100 elements:
  Average time for array_flip(): 0.00018
  Average time for foreach: 0.00038
  How much array_flip() is faster: 114%

Testing an array with 1000 elements:
  Average time for array_flip(): 0.00138
  Average time for foreach: 0.00363
  How much array_flip() is faster: 163%

Testing an array with 10000 elements:
  Average time for array_flip(): 0.01443
  Average time for foreach: 0.03644
  How much array_flip() is faster: 152%

Testing an array with 100000 elements:
  Average time for array_flip(): 0.15642
  Average time for foreach: 0.37017
  How much array_flip() is faster: 136%

Testing an array with 1000000 elements:
  Average time for array_flip(): 1.38271
  Average time for foreach: 3.75081
  How much array_flip() is faster: 171%
Run Code Online (Sandbox Code Playgroud)

你看到了吗?大约array_flip()快 2.5 倍。此外,array_flip()当数组变大时,它的性能似乎略有提高。所以,忘记foreach。即使有 JIT 的帮助?继续阅读...

JIT 能帮上忙吗?

是的,但并非如您所料。这是 PHP 8.0.0-beta2 的结果,启用了 JIT ( opcache.jit = 1235, opcache.jit_buffer_size = 100M):

Testing an array with 10 elements:
  Average time for array_flip(): 6.0E-5
  Average time for foreach: 4.0E-5
  How much array_flip() is faster: -29%

Testing an array with 100 elements:
  Average time for array_flip(): 0.00014
  Average time for foreach: 0.00025
  How much array_flip() is faster: 82%

Testing an array with 1000 elements:
  Average time for array_flip(): 0.00124
  Average time for foreach: 0.00249
  How much array_flip() is faster: 100%

Testing an array with 10000 elements:
  Average time for array_flip(): 0.01201
  Average time for foreach: 0.02412
  How much array_flip() is faster: 100%

Testing an array with 100000 elements:
  Average time for array_flip(): 0.14584
  Average time for foreach: 0.25029
  How much array_flip() is faster: 71%

Testing an array with 1000000 elements:
  Average time for array_flip(): 1.26789
  Average time for foreach: 2.54315
  How much array_flip() is faster: 100%
Run Code Online (Sandbox Code Playgroud)

你可以注意到正在发生的事情。所以:

  • JIT 让一切变得更快。对于array_flip(),它大约提高了 10-20% 的性能,对于foreach循环,大约提高了 30-40%。因此,它比内部函数更能提高本机 PHP 代码的性能,这在意料之中。

  • 由于前面的说明,这两种方法之间的差异减少了,尽管array_flip()快了近 2 倍。所以,JIT 很棒,但它不是一个超级神奇的东西。

所以,不考虑你的 PHP 版本和配置,内部函数大多更快。再次,使用array_flip().

话费便宜...

这是我测试的(您可以随意配置变量):

// The ratio of array size being increased
$arraySizeBase = 10;
// Limits of the exponention of the array size
$arraySizePowerMin = 1;
$arraySizePowerMax = 6;

// Number of tests being run within one time capture
$iterationsCount = 100;
// Number of time capture repeats
$repeatCount = 20;
// Precision of rounded result
$precision = 5;

// Array values limits
$minVal = 0;
$maxVal = 10000;

function printTime(callable $x, string $title)
{
    global $iterationsCount, $repeatCount, $precision;

    $tests = [];
    for ($i = 0; $i < $repeatCount; $i++) {
        $startTime = microtime(true);

        for ($j = 0; $j < $iterationsCount; $j++) {
            $x();
        }

        $tests[] = microtime(true) - $startTime;
    }

    $averageTime = array_sum($tests) / $repeatCount;
    echo "  Average time for $title: ", round($averageTime, $precision), PHP_EOL;

    // To be used to calculate ratio
    return $averageTime;
}

$arraySizeMin = $arraySizeBase ** $arraySizePowerMin;
$arraySizeMax = $arraySizeBase ** $arraySizePowerMax;

for ($i = $arraySizeMin; $i <= $arraySizeMax; $i *= $arraySizeBase) {
    // Filling the array with some random stuff
    echo "Testing an array with $i elements:", PHP_EOL;
    $array = array_fill(0, $i - 1, random_int($minVal, $maxVal));

    $arrayFlipTime = printTime(function () use ($array) {
        $flippedArray = array_flip($array);

        // Don't be crazy, clean RAM
        $flippedArray = null;
    }, "array_flip()");

    $foreachTime = printTime(function () use ($array) {
        $flippedArray = [];
        foreach ($array as $key => $value) {
            $flippedArray[$value] = $key;
        }

        // Don't be crazy, clean RAM
        $flippedArray = null;
    }, "foreach");

    // Print a ratio in percentage
    echo "  How much array_flip() is faster: ",
        floor(($foreachTime / $arrayFlipTime) * 100) - 100, "%",
        PHP_EOL;

    echo PHP_EOL;
}
Run Code Online (Sandbox Code Playgroud)