一、yield介绍

 文档介绍说道:生成器函数的核心是yield关键字。它最简单的调用形式看起来像一个return申明,不同之处在于普通return会返回值并终止函数的执行,而yield会返回一个值给循环调用此生成器的代码并且只是暂停执行生成器函数。

 说了这么多到底是个东西呢,只有自己亲自动手写代码才知道。


二、range函数探索

 1、首先看下我们常用的一个产生数组的函数range()

	$ran = range(1, 100);

	var_dump($ran)//可以看到是一个产生了一个数组

	//既然是数组就来遍历看下效果吧
foreach (range(1, 100) as $num) {
echo $num.PHP_EOL;
}
 

 2、现在我们自己来实现这个range()函数

	function my_range($start,$limit){
$arr = [];
for($i=$start;$i<=$limit;$i++){
$arr[] =$i;
}
return $arr;
}
 

 了解了这个函数构造后,发现并没有什么神奇的地方,那生成器和这个有什么关系呢,继续往下看。


三、内存占用

 1、当我们遍历的范围很小的时候还看不到什么问题,当我们要遍历的数字很大就会超过PHP的内存限制,这下使用生成器就非常有必要了。

 2、我们先看上面的range(1, 100)产生的数组占用了多少内存

	$start = memory_get_usage();
echo $start.' bytes'.PHP_EOL;
$arr = range(1, 100);
$end = memory_get_usage();
echo $end - $start .' bytes'.PHP_EOL;
 

 结果为:8280 bytes

 3、试着增大数字的范围可以看到占用的内存越来越大,下面是我的一组在CLI模式测试的占用内存情况

	// 10  	     728 bytes
// 100 8280 bytes
// 1000 36952 bytes
// 10000 528472 bytes
// 100000 6291568 bytes
// 1000000 35651696 bytes
 

 如果继续增加到10000000,就会报错。根据个人设置PHP内存上限而定。我设置的是512M。

Fatal error: Allowed memory size of 536870912 bytes exhausted (tried to allocate 536870920 bytes) in C:\wamp64\www\phpdemo\yield.php on line 31
 

 4、如果我们就是要操作很大的数字遍历,除了调整内存限制,就无计可施了嘛,这下我们的生成器就要隆重登场了。


四、生成器

 1、上面我们自己实现了range()方法,这次我们重新使用生成器来实现这个方法

	function  my_range($start,$limit){
for($i=$start;$i<=$limit;$i++){
yield $i;
}
}
 

 2、打印出来,看下返回究竟是什么

	$arr = my_range(1,100);
var_dump($arr);
 
  • 1
  • 2

 结果是:

	object(Generator)#1 (0) {
}
 

 可见是一个对象,是一个生成器对象,既然是对象那么也就是可以用foreach来遍历

 3、遍历生成器

	foreach($arr as $num){
echo $num.PHP_EOL;
}
 

 看到可以完整遍历出来,那么与那样实现的不同地方,意义在哪里呢。重点来了。

 4、两者内存占用比较

  上面已经测试过使用数组的方式,随着范围的增大占用的内存剧增,很快就超过了PHP的内存上限。

  那么使用生成器占用了多少内存呢,来看看就知道了。

	$start = memory_get_usage();
$arr = my_range(1, 100);
$end = memory_get_usage();
echo $end - $start .' bytes'.PHP_EOL;
 

  可以看到只占用了576bytes,当然每个人测试的可能都会有点不同,环境不同,但是这不是重点。

  我们再尝试增加数字范围,可以看到数字范围并没有影响到内存占用,也就是可以轻松的遍历超大数字。

	$start = memory_get_usage();
$arr = my_range(1, 100000000);
$end = memory_get_usage();
echo $end - $start .' bytes'.PHP_EOL; foreach($arr as $num){
echo $num.PHP_EOL;
}
 

  这下我们就可以遍历1到10000000的数字了,不相信内存占用那么低的小伙伴,可以打开任务管理器毫无波澜,即时再上调数字范围。

 5、生成器遍历原理

  生成器既然这么强大,那么他的遍历原理是什么呢。使用foreach遍历的时候,相当于生成器执行了以下操作。

	while($arr->valid()){
echo $arr->current().PHP_EOL;
$arr->next();
}
//$arr->valid() 判断生成器是否关闭
//$arr->current() 返回当前对象
//$arr->next() 继续往下执行生成器
 

五、结后语

  你以为生成器就只有这些用处吗,当然不止。可以使用在很多大量数据的获取场景中,一次性从数据库读取超多的数据,一次性从文本读取超多行文本,都可以这样处理。

  不仅用于解决内存问题,还有其他的用武之地,只因本人才疏学浅只能先探索这么多了。

 

php生成器 yield 转的更多相关文章

  1. Python入门之迭代器/生成器/yield的表达方式/面向过程编程

    本章内容 迭代器 面向过程编程 一.什么是迭代 二.什么是迭代器 三.迭代器演示和举例 四.生成器yield基础 五.生成器yield的表达式形式 六.面向过程编程 ================= ...

  2. PHP性能优化利器:生成器 yield理解

    如果是做Python或者其他语言的小伙伴,对于生成器应该不陌生.但很多PHP开发者或许都不知道生成器这个功能,可能是因为生成器是PHP 5.5.0才引入的功能,也可以是生成器作用不是很明显.但是,生成 ...

  3. [PY3]——函数——生成器(yield关键字)

    函数—生成器篇 1. 认识和区分可迭代or生成器 1.1 可迭代对象 当你建立了一个列表,你可以逐项地读取这个列表,这叫做一个可迭代对象 当你使用一个列表生成式来建立一个列表的时候,就建立了一个可迭代 ...

  4. 6 生成器 yield 协程

    1.生成器 ----> 1 b = [x*2 for x in range(100000000000)] MemoryError: 想生成一个存放很多数据的列表,但是又不想内存占用太多 每次用一 ...

  5. day4 内置函数 迭代器&生成器 yield总结 三元运算 闭包

    内置函数: 内置函数 # abs()返回一个数字的绝对值.如果给出复数,返回值就是该复数的模. b = -100 print(b) print(abs(b)) # all() 所有为真才为真,只要有一 ...

  6. PHP 生成器 yield理解

    如果是做Python或者其他语言的小伙伴,对于生成器应该不陌生.但很多PHP开发者或许都不知道生成器这个功能,可能是因为生成器是PHP 5.5.0才引入的功能,也可以是生成器作用不是很明显.但是,生成 ...

  7. python3使用迭代生成器yield减少内存占用

    技术背景 在python编码中for循环处理任务时,会将所有的待遍历参量加载到内存中.其实这本没有必要,因为这些参量很有可能是一次性使用的,甚至很多场景下这些参量是不需要同时存储在内存中的,这时候就会 ...

  8. Two---python循环语句/迭代器生成器/yield与return/自定义函数与匿名函数/参数传递

    python基础02 条件控制 python条件语句是通过一条或多条语句的执行结果(Ture或者False)来执行的代码块 python中用elif代替了else if,所以if语句的关键字为:if- ...

  9. Python全栈之路8--迭代器(iter)和生成器(yield)

    一.生成器( iter ) 从Python2.2起,生成器提供了一种简洁的方式帮助返回列表元素的函数来完成简单和有效的代码. 它基于yield指令,允许停止函数并立即返回结果.此函数保存其执行上下文, ...

  10. (转) Python Generators(生成器)——yield关键字

    http://blog.csdn.net/scelong/article/details/6969276 生成器是这样一个函数,它记住上一次返回时在函数体中的位置.对生成器函数的第二次(或第 n 次) ...

随机推荐

  1. oracle之三目录库和辅助库

    目录库和辅助库 10.1 创建目录库(Catalog database)的必要性 如果没有catalog,RMAN的存储库(元数据)保存在目标库的控制文件里,这样可能存在如下隐患 1)目标库上的控制文 ...

  2. HarmonyOS面向128KB-128MB内存终端开源

    2020年9月10日,以HDC Together为主题的2020年度华为开发者大会在东莞·松山湖举办,华为带来了HarmonyOS 2.0.EMUI 11.HMS.HUAWEI HiLink.HUAW ...

  3. top、ps -ef、ps aux的区别及内容详解

    1.top和ps的区别 ps是静态查看进程--------top是动态(持续监控)进程 ps只是查看进程-----------top还可以监视系统性能,如平均负载,cpu和内存的消耗 2.ps -ef ...

  4. hystrix动态修改参数

    Hystrix 从入门到深入——运行时修改动态配置 /** * * @author zhangshuo * */ @Component public class DynamicConfigSource ...

  5. Mybatis快速逆向生成代码

    先下载生成器的文件, 并在eclipse或者IDEA里面打开这个工程 热乎乎的链接 然后配置一下 选择你需要生成的数据的ip和端口 点击运行入口函数 运行成功 接着在浏览器输入localhost: 这 ...

  6. python中yield的用法详解——最简单,最清晰的解释(转载)

    原文链接 首先我要吐槽一下,看程序的过程中遇见了yield这个关键字,然后百度的时候,发现没有一个能简单的让我懂的,讲起来真TM的都是头头是道,什么参数,什么传递的,还口口声声说自己的教程是最简单的, ...

  7. MyBatis学习(二)代码实战

    一.项目依赖 本项目是基于mybatis3.4.6版本实现的,用到的jar包如下 二.项目结构解析 三.配置文件解析 四.mapper文件解析 <?xml version="1.0&q ...

  8. 【Processing日常2】群星1

    之前在CSDN上发表过: https://blog.csdn.net/fddxsyf123/article/details/79747064

  9. Spring--AOP的见解

    AOP是指面向切面编程,与JAVA中的动态代理有很深的渊源. 在使用Spring框架时,AOP编程能简化很多繁杂的步骤,精简代码. 切面:横切关注点(跨越程序中多个模块的功能),被模块化的特殊对象,也 ...

  10. djano jwt 的使用

    1.5 JWT:使用djangorestframework-jwt模块进行用户身份验证    安装: pip install djangorestframework-jwt    添加应用:pytho ...