PHP性能优化利器:天生器 yield了解

2020-3-26 14:45| 发布者: 山人佳燕品| 查看: 83| 评论: 3

摘要: 如果是做Python或者其他语言的小伙伴,对于生成器应该不陌生。但很多PHP开发者或许都不知道生成器这个功能,可能是因为生成器是PHP 5.5.0才引入的功能,也可以是生成器作用不是很明显。但是,生成器功能的确非常有用 ...
假如是做Python大概其他说话的小伙伴,对于天生器应当不陌生。但很多PHP开辟者也许都不晓得天生器这个功用,能够是由于天生器是PHP 5.5.0才引入的功用,也可以是天生器感化不是很明显。可是,天生器功用简直很是有用。


优点
间接讲概念估量你听完还是一头雾水,所以我们先来说说优点,也许能勾起你的爱好。那末天生器有哪些优点,以下:
  • 天生器会对PHP利用的性能有很是大的影响
  • PHP代码运转时节省大量的内存
  • 比力合适计较大量的数据


那末,这些奇异的功用究竟是若何做到的?我们先来举个例子。
概念引入
首先,放下天生器概念的负担,来看一个简单的PHP函数:
function createRange($number){
$data = [];
for($i=0;$i<$number;$i++){
$data[] = time();
}
return $data;
}


这是一个非经常见的PHP函数,我们在处置一些数组的时辰经常会利用。这里的代码也很是简单:
  1. 我们建立一个函数。
  2. 函数内包括一个 for 循环,我们循环的把当前时候放到$data里面
  3. for循环履行终了,把 $data 返回进来。


下面没完,我们继续。我们再写一个函数,把这个函数的返回值循环打印出来:

$result = createRange(10); // 这里挪用上面我们建立的函数
foreach($result as $value){
sleep(1);//这里搁浅1秒,我们后续有用
echo $value.'
';
}


我们在阅读器里面看一下运转成果:

PHP性能优化利器:天生器 yield了解


这里很是完善,没有任何题目。(固然 sleep(1) 结果你们看不出来)
思考一个题目
我们留意到,在挪用函数 createRange 的时辰给 $number 的传值是10,一个很小的数字。假定,现在传递一个值10000000(1000万)。那末,在函数 createRange 里面,for循环就需要履行1000万次。且有1000万个值被放到 $data 里面,而$data数组在是被放在内存内。所以,在挪用函数时辰会占用大量内存。这里,天生器便可以大显神通了。
建立天生器
我们间接点窜代码,你们留意观察:
function createRange($number){
for($i=0;$i<$number;$i++){
yield time();
}
}


看下这段和刚刚很像的代码,我们删除了数组 $data ,而且也没有返回任何内容,而是在 time() 之前利用了一个关键字yield。
利用天生器
我们再运转一下第二段代码:
$result = createRange(10); // 这里挪用上面我们建立的函数
foreach($result as $value){
sleep(1);
echo $value.'
';
}

PHP性能优化利器:天生器 yield了解


我们奇迹般的发现了,输出的值和第一次没有益用天生器的纷歧样。这里的值(时候戳)中心间隔了1秒。
这里的间隔一秒实在就是 sleep(1) 酿成的结果。可是为什么第一次没有间隔?那是由于:
  • 未利用天生器时: createRange 函数内的 for 循环成果被很快放到 $data 中,而且立即返回。所以, foreach 循环的是一个牢固的数组。
  • 利用天生器时: createRange 的值不是一次性快速天生,而是依靠于 foreach 循环。 foreach 循环一次, for 履行一次。


到这里,你应当对天生器有点儿眉目。
深入了解天生器
代码分解
下面我们来对于刚刚的代码停止分解。
function createRange($number){
for($i=0;$i<$number;$i++){
yield time();
}
}

$result = createRange(10); // 这里挪用上面我们建立的函数
foreach($result as $value){
sleep(1);
echo $value.'
';
}


我们来复原一下代码履行进程。
  1. 首先挪用 createRange 函数,传入参数10,可是 for 值履行了一次然后停止了,而且告诉 foreach 第一次循环可以用的值。
  2. foreach 起头对 $result 循环,进来首先 sleep(1) ,然后起头利用 for 给的一个值履行输出。
  3. foreach 预备第二次循环,起头第二次循环之前,它向 for 循环又请求了一次。
  4. for 循环因而又履行了一次,将天生的时候戳告诉 foreach .
  5. foreach 拿到第二个值,而且输出。由于 foreach 中 sleep(1) ,所以, for 循环提早了1秒天生当前时候


所以,全部代码履行中,始终只要一个记录值介入循环,内存中也只要一条信息。不管起头传入的 $number 有多大,由于并不会立即天生一切成果集,所之内存始终是一条循环的值。
概念了解
到这里,你应当已经大要了解什么是天生器了。下面我们来说下天生器道理。
首先明白一个概念:天生器yield关键字不是返回值,他的专业术语叫产出值,只是天生一个值
那末代码中 foreach 循环的是什么?实在是PHP在利用天生器的时辰,会返回一个 Generator 类的工具。 foreach 可以对该工具停止迭代,每一次迭代,PHP会经过 Generator 实例计较出下一次需要迭代的值。这样 foreach 就晓得下一次需要迭代的值了。
而且,在运转中 for 循环履行后,会立即停止。期待 foreach 下次循环时辰再次和 for 索要下次的值的时辰,循环才会再履行一次,然后立即再次停止。直到不满足条件不履行竣事。


现实开辟利用
很多PHP开辟者不领会天生器,实在主如果不领会利用范畴。那末,天生器在现实开辟中有哪些利用?
读取超大文件
PHP开辟很多时辰都要读取大文件,比如csv文件、text文件,大概一些日志文件。这些文件假如很大,比如5个G。这时,间接一次性把一切的内容读取到内存入彀较不太现实。
这里天生器便可以派上用处啦。简单看个例子:读取text文件

PHP性能优化利器:天生器 yield了解


我们建立一个text文本文档,并在其中输入几行笔墨,树模读取。
header("content-type:text/html;charset=utf-8");
function readTxt()
{
# code...
$handle = fopen("./test.txt", 'rb');

while (feof($handle)===false) {
# code...
yield fgets($handle);
}

fclose($handle);
}

foreach (readTxt() as $key => $value) {
# code...
echo $value.'
';
}

PHP性能优化利器:天生器 yield了解


经过上图的输出成果我们可以看出代码完全一般。可是,背后的代码履行法则却一点儿也纷歧样。利用天生器读取文件,第一次读取了第一行,第二次读取了第二行,以此类推,每次被加载到内存中的笔墨只要一行,大大的减小了内存的利用。
这样,即使读取上G的文本也不用担忧,完全可以像读取很小文件一样编写代码。

百万级此外拜候量

yield天生器是php5.5以后出现的,yield供给了一种更轻易的方式来实现简单的迭代工具,相比力界说类实现 Iterator 接口的方式,性能开销和复杂性大大下降。yield天生器答应你 在 foreach 代码块中写代码来迭代一组数据而不需要在内存中建立一个数组。

路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部