1

所以我制作了这个简单的脚本来测试SplFixedArray对象,看看它的性能如何。

使用数组的传统方法

ini_set('memory_limit', '2048M');
$start    = microtime(true);
$memStart = memory_get_peak_usage(true);
$loop     = 1000000;
$array    = [];

for ($i = 0; $i < $loop; ++$i) {
    $arr       = ['a'];
    $array[$i] = $arr;
}

$end    = microtime(true);
$memEnd = memory_get_peak_usage(true);
echo 'Time: ' . ($end - $start) . "\n";
echo 'Mem: ' . ($memEnd - $memStart) / 1024 / 1024 . 'Mb';

//Display: Time: 0.037514925003052 Mem: 28Mb

SplFixedArray

ini_set('memory_limit', '2048M');
$start    = microtime(true);
$memStart = memory_get_peak_usage(true);
$loop     = 1000000;
$array    = new SplFixedArray($loop);

for ($i = 0; $i < $loop; ++$i) {
    $arr       = new SplFixedArray(1);
    $arr[0]    = 'a';
    $array[$i] = $arr;
}

$end    = microtime(true);
$memEnd = memory_get_peak_usage(true);
echo 'Time: ' . ($end - $start) . "\n";
echo 'Mem: ' . ($memEnd - $memStart) / 1024 / 1024 . 'Mb';

//Display: Time: 0.21888899803162 Mem: 142Mb (slower by 5x)

从文档中,不是SplFixedArray承诺具有更好的性能和内存吗?为什么会这样。那么究竟应该在什么情况下使用呢?

4

2 回答 2

4

是一种特殊类型的SplFixedArray对象,通常表现为数组,但有以下限制:

  1. 与常规数组不同 -SplFixedArray具有固定大小。
  2. 与常规数组不同 -SplFixedArray的键只能是整数。

由于这两个特点 - 数组上的方法的实现SplFixedArray可以更快。

至于您的示例 - 请注意,在第二个示例中,您创建了 100000 个新SplFixedArray对象(与第一个示例不同,您仅创建了 1 个数组)。

SplFixedArray以您的示例为例-当在循环中删除 new 的创建时,只需将值设置a为数组的每个元素-这就是我得到的:

$start = microtime(true);
$memStart = memory_get_peak_usage(true);
$loop = 100000;
$array = new SplFixedArray($loop);


for ($i = 0; $i<$loop; $i++) {
    $array[$i] = 'a';
}

$end = microtime(true);
$memEnd = memory_get_peak_usage(true);
echo "Time: " . ($end - $start) . "\n";
echo "Mem: " . ($memEnd - $memStart)/1024/1024 . 'Mb';

// Time: 0.0023539066314697 Mem: 2Mb

请注意,我更改为 microtime

这里要记住的另一件重要的事情 - 文档中提到的“更快的数组实现”与可以在SplFixedArray对象上使用的类数组函数有关。

于 2019-12-01T23:52:36.557 回答
1

SplFixedArray对于为其设计的特定用例更有效。如果它更快并且对所有内容使用更少的内存,它将简单地实现为所有数组的默认值,并且实际上 PHP 7 会根据您使用每个数组的方式自动在多个实现之间进行选择。

拥有固定长度数组的想法是,通过预先设置长度,引擎不需要猜测要分配多少内存,并在您使数组更长或更短时重新排列内存。因此,为了比较它们,我们需要使用一个可以产生影响的基准,例如从一个空数组开始并向其中添加一百万个元素:

$loop     = 1000000;
$array    = [];

for ($i = 0; $i < $loop; ++$i) {
    $array[] = 42;
}

对比

$loop     = 1000000;
$array    = new SplFixedArray(1000000);

for ($i = 0; $i < $loop; ++$i) {
    $array[$i] = 42;
}

请注意,我只创建一个数组或一个SplFixedArray,因为创建许多小数组不是我们正在测试的情况。

在 PHP 7.2 机器上,我必须得到以下基准:

  • 阵列:220ms,32Mb
  • SplFixedArray:211ms,15Mb

在 PHP 5.6 上,差异更加显着,显示了内部数组实现在最近版本中的改进:

  • 阵列:450ms,138Mb
  • SplFixedArray:320ms,53.75Mb

SplFixedArray像大多数基准测试一样,这可能与真实世界的代码不同,但它显示了一种使用 an会带来明显优势的场景。

您可以四处玩耍,可能会发现更大的差异,例如

  • 随机分配元素,而不是按顺序分配,因此 PHP 更难猜测最终长度。
  • 删除元素以及添加它们。
  • 从数组中读取,或迭代它foreach

相反,我们可以通过根本不分配给外部数组来简化您的测试用例以查看减速的位置:

$loop     = 1000000;

for ($i = 0; $i < $loop; ++$i) {
        $array    = new SplFixedArray(1);
}

这需要 1.5 秒或更长时间才能在我的 PHP 7.2 机器上运行,而如果我编写$array = []. SplFixedArray显然,在选择是否使用它们时需要考虑创建新实例的成本。

对于“多维数组”,这可能是一个重要因素,因为无法预先分配多个维度,您必须为外部数组中的每个项目创建新实例。可以实现不同的结构来优化这种情况,但从 7.4 版开始,PHP 没有内置任何结构。

于 2019-12-02T15:05:29.427 回答