你有没有想过 "在 PHP 中使用 yield 会有什么益处",我将为你节省一些谷歌搜索的时间; 我列出了一些要向你介绍的要点来全面认知 yield

  1. 什么是 yield
  2. yield & return 的区别。
  3. yield 有什么选项。
  4. 结论。
  5. 参考。

1. 什么是 "yield"

生成器函数看上去就像一个普通函数, 除了不是返回一个值之外, 生成器会根据需求产生更多的值。

来看以下的例子:

function getValues() {
yield 'value';
} // 输出字符串 "value"
echo getValues();

当然, 这不是他生效的方式, 前面的例子会给你一个致命的错误: 类生成器的对象不能被转换成字符串, 让我们清楚的说明:

2. "yield" & "return" 的区别

前面的错误意味着 getValues() 方法不会如预期返回一个字符串,让我们检查一下他的类型:

function getValues() {
return 'value';
}
var_dump(getValues()); // string(5) "value" function getValues() {
yield 'value';
}
var_dump(getValues()); // class Generator#1 (0) {}

生成器 类实现了 生成器 接口, 这意味着你必须遍历 getValue() 方法来取值:

foreach (getValues() as $value) {
echo $value;
} // 使用变量也是好的
$values = getValues();
foreach ($values as $value) {
echo $value;
}

但这不是唯一的不同!

一个生成器运行你写使用循环来迭代一维数组的代码,而不需要在内存中创建是一个数组,这可能会导致你超出内存限制。

在下面的例子里我们创建一个有 800,000 元素的数字同时从 getValues() 方法中返回他,同时在此期间,我们将使用函数 memory_get_usage() 来获取分配给次脚本的内存, 我们将会每增加 200,000 个元素来获取一下内存使用量,这意味着我们将会提出四个检查点:

<?php
function getValues() {
$valuesArray = [];
// 获取初始内存使用量
echo round(memory_get_usage() / 1024 / 1024, 2) . ' MB' . PHP_EOL;
for ($i = 1; $i < 800000; $i++) {
$valuesArray[] = $i;
// 为了让我们能进行分析,所以我们测量一下内存使用量
if (($i % 200000) == 0) {
// 来 MB 为单位获取内存使用量
echo round(memory_get_usage() / 1024 / 1024, 2) . ' MB'. PHP_EOL;
}
}
return $valuesArray;
}
$myValues = getValues(); // 一旦我们调用函数将会在这里创建数组
foreach ($myValues as $value) {}

前面例子发生的情况是这个脚本的内存消耗和输出:

0.34 MB
8.35 MB
16.35 MB
32.35 MB

这意味着我们的几行脚本消耗了超过 30 MB 的内存, 每次你你添加一个元素到 $valuesArray 数组中, 都会增加他在内存中的大小。

让我们使用 yield 同样的例子:

<?php
function getValues() {
// 获取内存使用数据
echo round(memory_get_usage() / 1024 / 1024, 2) . ' MB' . PHP_EOL;
for ($i = 1; $i < 800000; $i++) {
yield $i;
// 做性能分析,因此可测量内存使用率
if (($i % 200000) == 0) {
// 内存使用以 MB 为单位
echo round(memory_get_usage() / 1024 / 1024, 2) . ' MB'. PHP_EOL;
}
}
}
$myValues = getValues(); // 在循环之前都不会有动作
foreach ($myValues as $value) {} // 开始生成数据

这个脚本的输出令人惊讶:

0.34 MB
0.34 MB
0.34 MB
0.34 MB

这不意味着你从 return 表达式迁移到 yield,但如果你在应用中创建会导致服务器上内存出问题的巨大数组,则 yield 更加适合你的情况。


3. 什么是 "yield" 选项

这里有很多 yield 的选项, 我将强调他们中的几个:

a. 使用 yield, 你也可以使用 return

function getValues() {
yield 'value';
return 'returnValue';
}
$values = getValues();
foreach ($values as $value) {}
echo $values->getReturn(); // 'returnValue'

b. 返回键值对:

function getValues() {
yield 'key' => 'value';
}
$values = getValues();
foreach ($values as $key => $value) {
echo $key . ' => ' . $value;
}

点击 这里 查看更多。

4. 结论

这个主题的主要原因是为了明确 yieldreturn 特别是在内存使用方面的区别,使用一些例子是因为我发现他对任何开发人员思考真的很重要。

5. 参考

  1. http://php.net/manual/en/language.generators.syntax.php
  2. http://php.net/manual/en/class.generator.php
  3. http://php.net/manual/en/language.generators.php
  4. http://php.net/manual/en/function.memory-get-usage.php

讨论请前往:https://laravel-china.org/topics/8704

作者:summerbluet
链接:https://www.jianshu.com/p/103cbf359971

在 PHP 中使用 `yield` 来做内存优化的更多相关文章

  1. android 开发如何做内存优化

    不少人认为JAVA程序,因为有垃圾回收机制,应该没有内存泄露.其实如果我 们一个程序中,已经不再使用某个对象,但是因为仍然有引用指向它,垃圾回收器就无法回收它,当然该对象占用的内存就无法被使用,这就造 ...

  2. redis 如何做内存优化?

    1.缩减键值对象 缩减键(key)和值(value)的长度, key长度:如在设计键时,在完整描述业务情况下,键值越短越好. value长度:值对象缩减比较复杂,常见需求是把业务对象序列化成二进制数组 ...

  3. Redis如何做内存优化?

    1.缩减键值对象 缩减键(key)和值(value)的长度, key长度:如在设计键时,在完整描述业务情况下,键值越短越好. value长度:值对象缩减比较复杂,常见需求是把业务对象序列化成二进制数组 ...

  4. 【腾讯Bugly干货分享】Android内存优化总结&实践

    本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/2MsEAR9pQfMr1Sfs7cPdWQ 导语 智 ...

  5. redis的内存优化【转】

    Redis所有的数据都在内存中,而内存又是非常宝贵的资源.对于如何优化内存使用一直是Redis用户非常关注的问题.本文让我们深入到Redis细节中,学习内存优化的技巧.分为如下几个部分: 一.redi ...

  6. [转]探索 Android 内存优化方法

    前言 这篇文章的内容是我回顾和再学习 Android 内存优化的过程中整理出来的,整理的目的是让我自己对 Android 内存优化相关知识的认识更全面一些,分享的目的是希望大家也能从这些知识中得到一些 ...

  7. Redis之内存优化

    Redis所有的数据都存在内存中,当前内存虽然越来越便宜,但跟廉价的硬盘相比成本还是比较昂贵,因此如何高效利用Redis内存变得非常重要.高效利用Redis内存首先需要理解Redis内存消耗在哪里,如 ...

  8. 试试SQLSERVER2014的内存优化表

    试试SQLSERVER2014的内存优化表 SQL Server 2014中的内存引擎(代号为Hekaton)将OLTP提升到了新的高度. 现在,存储引擎已整合进当前的数据库管理系统,而使用先进内存技 ...

  9. android内存优化

    背景 虽然android设备的配置越来越高,但是,由于android系统的机制导致(最主要是app程序的主线程不会真正退出而是在后台常驻内存中) ,这样手机中安装过多的app之后,导致内存被大量占用, ...

随机推荐

  1. ASP.NET MVC5 + EF6 + LayUI实战教程,通用后台管理系统框架(3)

    前言 本节将我们自己的CSS样式替换系统自带的 开始搭建 将脚本文件夹删掉,将内容文件夹里的内容删掉,将我们自己的CSS样式文件,全部复制到内容里边 新建家庭控制器 给家庭控制器添加索引视图 指数代码 ...

  2. 使用 libjpeg 库解压数据示例

    static int MjpegDecompress( *** ) { struct jpeg_decompress_struct tDInfo; struct jpeg_error_mgr jerr ...

  3. JavaScript字符串常用方法

    toUpperCase():把一个字符串全部变为大写 toLowerCase():把一个字符串全部变为小写 indexOf():会搜索制定字符串出现的位置,有返回索引,没有返回-1 substring ...

  4. ASP.NET Identity系列教程(目录)转载

    来源:http://www.cnblogs.com/r01cn/p/5179506.html 注:最近看到不少介绍微软ASP.NET Identity技术的文章,但感觉都不够完整深入,本人又恰好曾在A ...

  5. 算法第四版-文字版-下载地址-Robert Sedgewick

    下载地址:https://download.csdn.net/download/moshenglv/10777447 算法第四版,文字版,可复制,方便copy代码 目录: 第1章 基 础 ...... ...

  6. SVN多分支开发模式V1.0.1

    1目的 规范开发模式过程,指导项目研发.质控测试.DevOps的相关活动. 2适用范围 本规范的作用范围是为互联网软件产品相关项目开发模式的管理过程. (1)   对项目团队中研发人员在开发模式过程中 ...

  7. Nginx学习笔记(三)--- Nginx实现反向代理和配置负载均衡

    1.反向代理 2.Nginx反向代理流程图 3.安装多个tomcat 3.1把tomcat的压缩包传到Linux上 3.2 解压tomcat 3.3 给压缩好的tomcat改个名字用来区分一下 3.4 ...

  8. git 命令小总结

    下载代码 git clone http://admin@192.168.0.208:7990/scm/klvchen/tale.git 设置用默认户名和密码登录,注意 URI 前面不允许有 http, ...

  9. BZOJ3413: 匹配(后缀自动机 线段树合并)

    题意 题目链接 Sol 神仙题Orz 后缀自动机 + 线段树合并... 首先可以转化一下模型(想不到qwq):问题可以转化为统计\(B\)中每个前缀在\(A\)中出现的次数.(画一画就出来了) 然后直 ...

  10. 洛谷P1742 最小圆覆盖(计算几何)

    题意 题目链接 Sol 暴力做法是\(O(n^3)\)枚举三个点然后check一下是否能包含所有点 考虑一种随机算法,首先把序列random_shuffle一下. 然后我们枚举一个点\(i\),并维护 ...