在symfony中,看到对于对象的生成使用了yield,而不是return,由此对yield有了一个认识。
关于yield可以参考php官网:https://www.php.net/manual/zh/language.generators.overview.php
官网上有解释说,yield会节省php的内存,为了证明这个问题,我也借鉴php官网的demo进行了测试,代码如下
range.php
echo memory_get_peak_usage();
echo PHP_EOL;
$startTime = microtime(true);
foreach (range(1, 10000) as $key => $value) {
}
$endTime = microtime(true);
echo PHP_EOL;
echo memory_get_peak_usage();
echo PHP_EOL;
echo '时间'.(bcsub($endTime, $startTime , 3) * 1000). '毫秒';
运行结果如下:
运行前分配内存:426424B
运行后分配内存:921112B
运行时间:1毫秒
使用了yield之后
xrange.php
function xrange($start, $end)
{
for ($i = $start; $i <= $end; $i++) {
yield $i;
}
}
echo memory_get_peak_usage().PHP_EOL;
$startTime = microtime(true);
foreach (xrange(1, 10000) as $k => $value) {
}
$endTime = microtime(true);
echo PHP_EOL.memory_get_peak_usage().PHP_EOL;
echo '时间'.(bcsub($endTime, $startTime , 3) * 1000). '毫秒';
运行结果如下:
运行前分配内存:429208
运行后分配内存:429208
运行时间:12毫秒
关于运行的对比和分析:
1.很明显可以看到使用了yield之后内存的使用率很低,几乎没有分配多余的内存,但是它的代价也很明显,运行时间大大增加,可以看为是一种以时间换取空间的做法。
2.为什么会有这样的情况?首先yield之后,我们打印xrange(1, 10000)函数的运行结果,发现它是一个生成器类,关于生成器的文档请看官方
https://www.php.net/manual/zh/class.generator.php
class Generator#1 (0) {
}
当然,我们也可以通过api对该类进行操作。
3.关于为何有这样的情况,自我认识如下:
内存为何降低:
数组的存放会占用内存,数据的越多,占用内存越多。
yield会生成一个生成器,内部跟踪生成器来当前状态。
时间为何会增多:
php数组内部的实现是通过hash表来实现的,遍历的速度自然很快。
关于生成器的数据结构,认为是通过链表来实现的(没有找到相关知识,保留疑问),两者的时间复杂度自然不同。