为什么PHP生成器比数组慢?

13
根据文档中的评论:http://php.net/manual/en/language.generators.overview.php,我们可以看到由于生成器的存在,内存使用大幅改善(这是显而易见的),但执行速度也慢了2-3倍,这一点对我来说不太明显。

我们以时间为代价来获得内存使用的改进 - 这是不好的。
那么,为什么PHP生成器比数组慢呢?

感谢技巧。


因为它必须运行代码来获取我们没有获取以节省内存的东西? - Niet the Dark Absol
@NiettheDarkAbsol 是的,但在文档中,它被提供为解决时间问题的解决方案:“生成器允许您编写使用foreach迭代一组数据的代码,而无需构建内存中的数组,这可能会导致您超出内存限制,或需要大量处理时间来生成”。 - szymanskilukasz
1个回答

12

在进行优化时,很多时候你必须在执行速度和内存使用之间做出选择,例如预先计算并存储某些内容或在需要时进行计算。

生成器允许您编写使用foreach迭代一组数据的代码,而无需构建一个数组在内存中,这可能会导致您超过内存限制,或者需要大量的处理时间来生成。

手册提到了当您不需要迭代通过生成器生成的所有结果时。速度上的好处在于您不需要浪费处理时间和内存来生成不需要的项目。

生成器并不是设计来替换数组的。它们旨在减少在实现迭代器对象时产生的样板代码。生成器始终比数组慢,因为每次调用next()时都必须生成值。

使用生成器可以做一些有趣的事情,这些事情使用数组是做不到的——例如,你可以表示无限序列(例如,你可以创建一个只接受起始和步长参数的range函数)。

我有点好奇,所以我快速比较了xrange(在PHP手册页面上使用生成器实现)和内置的range函数。

我的机器上的结果(使用PHP 5.6测试)是:

range(1, 10000000, 1):

time: 5.2702
memory (byte): 1495269376

xrange(1, 10000000, 1):

->

xrange(1, 10000000, 1):

(保留原文)
time: 1.9010
memory (byte): 262144
请注意,我使用的“基准”代码 正在 迭代所有结果并执行简单的数学操作。如上所示的函数调用仅作为我进行测试的值的参考。与此类非常简单的基准测试一样,实际结果可能有所不同。

请注意,我使用的“基准”代码正在迭代所有结果并执行简单的数学运算。如上所述的函数调用仅供我进行测试时的值参考。对于这种非常简单的基准测试,你的实际情况可能会有所不同。


1
参考链接:https://3v4l.org/gXnic/perf#output,https://3v4l.org/kbnNo/perf#output。由于3v4l提供的内存不多,因此我只使用了1.0e+5。 - SOFe
1
@SOFe 不错。当 N 更大时(即 100k),你会看到更大的差异(PHP 5.6 在两个版本中都表现不佳)。Range vs Generator - Christian P
1
正如人们所说,过早地进行优化是万恶之源。就像所有的优化一样,在进行更改之前,请测试和测量您的用例中的优化效果 :) - Christian P
这两个测试都涉及对g()进行100000次调用,其中g()要么创建一个0-9整数数组,要么生成0-9整数。截至PHP 7.2.4,通过用户时间计算,数组似乎比生成器快60%左右。这符合OP的描述。 - SOFe
@SOFe,就像我的回答所说 - “生成器并不是为了取代数组而设计的。它们旨在减少实现迭代器对象时的样板代码。”和“与数组相比,生成器始终会慢一些,因为每次调用next()时,生成器都必须生成值以节省内存。” 所以这里没有什么意外... 你可能只是误解了生成器的预期用途。 - Christian P
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接