PHP 生成器:性能优化利器

 2019-10-08 00:07:38   {{zan}}   0   42 

关于生成器,先简单介绍下,然后看两个例子对比一下。

生成器是在 PHP5.5.0 版本才引入的。存在意义就是:生成器提供了一种更容易的方法来实现简单的对象迭代,相比较定义类实现 Iterator 接口的方式,性能开销和复杂性大大降低

普通函数在 foreach 代码块中写代码来迭代一组数据需要把整个数组放在内存中处理,那么会使你的内存很容易达到上限,或者会占据很多的处理时间。

相反,使用生成器函数则不需要把整个数组放在内存中,生成器会使用迭代的方式,内存中始终只有一个数值存在。

看下两个简单的例子:

1. 普通函数:

我们可以改变代码中 $num 的值10,100,1000,10000,来对比内存占用情况的变化。

function createRange($num)
{
    $data = [];
    for ($i = 0; $i < $num; $i++) {
        $data[] = time();
    }
    return $data;
}
echo "普通函数: ".memory_get_usage()."<br/>";
$num = 10;
$result = createRange($num);
foreach($result as $value){
    echo $value.'--';
}
echo "普通函数: ".memory_get_usage()."<br/>";

打印结果:

image.png

由上可以做个表格:


$num的值10100
100010000100000
占用内存(byte)496
414428816397456419464

明显的看出随着 $num 值的增加,内存使用也随之增加。

2. 生成器函数:

如普通函数一样,改变 $num 的值10,100,1000,10000来看效果:

function createRange($num)
{
    for ($i = 0; $i < $num; $i++) {
        yield time();
    }
}
echo "生成器: ".memory_get_usage()."<br/>";
$num = 10;
$result = createRange($num);
foreach($result as $value){
    echo $value.'<br/>';
}
echo "生成器: ".memory_get_usage()."<br/>";

打印结果:

image.png

由上可以做个表格:


$num的值10100100010000100000
占用内存(byte)256
256352352352

明显的看出随着 $num 值的增加,内存使用也几乎不变。

首先明确一个概念:

生成器yield关键字不是返回值,他的专业术语叫产出值,只是生成一个值。

那么代码中foreach循环的是什么?其实是PHP在使用生成器的时候,会返回一个Generator类的对象。foreach可以对该对象进行迭代,每一次迭代,PHP会通过Generator实例计算出下一次需要迭代的值。这样foreach就知道下一次需要迭代的值了。

而且,在运行中for循环执行后,会立即停止。等待foreach下次循环时候再次和for索要下次的值的时候,for循环才会再执行一次,然后立即再次停止。直到不满足条件不执行结束。


实际应用:

假如我想要迭代一个大小为 5G 的 csv 文件,而我们服务器只允许PHP 使用 1GB内存,因此将整个文件加载到内存中是不可行的。

而使用生成器读取文件,第一次读取了第一行,第二次读取了第二行,以此类推,每次被加载到内存中的文字只有一行,大大的减小了内存的使用。这样,即使读取 5G 或者更多的 csv 文件或者 text 文件也可以像读取很小文件一样。


当然使不使用生成器还是要看具体情况。

附带官方的生成器介绍:https://www.php.net/manual/zh/language.generators.overview.php

本文链接地址:https://caohongyuan.cn/p?id=128

(邮箱不会公开,只会做回复通知用) 提交 清空 {{comment.content}}
Re:{{response.content}}