繁体   English   中英

PHP SplFixedArray 被窃听或性能下降?

[英]PHP SplFixedArray bugged or slow performance?

所以我制作了这个简单的脚本来测试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承诺具有更好的性能和内存吗? 为什么会这样。 那么究竟应该在什么情况下使用呢?

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

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

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

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

以您的示例为例 - 在循环内删除新SplFixedArray的创建时,只需将值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对象上使用的类似数组的函数有关。

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会带来明显优势的场景。

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

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

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

$loop     = 1000000;

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM