在PHP中使用“Yield”处理内存之php内存优化

2023-06-01 00:00:00 php 内存 内存优化

你有没有想过“在 PHP 中使用 yield 有什么好处”,我会帮你省去谷歌搜索的时间;

我有一个要点清单,我想向您介绍它以涵盖yield:

什么是yield。
yield和return的区别。
什么是yield选项。
结论。
参考。


1.什么是“yield”

一个生成器函数看起来就像一个普通的函数,除了它不返回一个值,生成器产生它需要的尽可能多的值。

看下面的例子:

function getValues() {
    yield 'value';
}
// print the string "value"
echo getValues();

当然,这不是它的工作方式,前面的例子会给你一个致命的错误: 

Object Of class Generator could not be convert to string,

让我们弄清楚


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) {}

Generator 类正在实现 Iterator 接口,这意味着您必须遍历 getValue() 函数才能获取值:

foreach (getValues() as $value) {
   echo $value;
}
// using variable is also alright
$values = getValues();
foreach ($values as $value) {
   echo $value;
}

但这不是唯一的区别!

生成器允许您编写使用 foreach 迭代一组数据的代码,而无需在内存中构建数组,这可能会导致您超出内存限制。


在下面的例子中,我们将构建一个包含 800,000 个元素的数组并从函数 getValues() 中返回它,

同时我们将使用函数 memory_get_usage() 获取分配给该脚本的内存,我们将获得内存使用情况每添加 200,000 个元素,

这意味着我们将放置四个检查点:

<?php
function getValues() {
   $valuesArray = [];
   // get the initial memory usage
   echo round(memory_get_usage() / 1024 / 1024, 2) . ' MB' . PHP_EOL;
   for ($i = 1; $i < 800000; $i++) {
      $valuesArray[] = $i;
      // let us do profiling, so we measure the memory usage
      if (($i % 200000) == 0) {
         // get memory usage in megabytes
         echo round(memory_get_usage() / 1024 / 1024, 2) . ' MB'. PHP_EOL;
      }
   }
   return $valuesArray;
}
$myValues = getValues(); // building the array here once we call the function
foreach ($myValues as $value) {}

在前面的示例中发生的是内存消耗和此脚本的输出:

0.34 MB
8.35 MB
16.35 MB
32.35 MB

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


让我们使用相同的示例来处理 yield:

<?php
function getValues() {
   // get the initial memory usage
   echo round(memory_get_usage() / 1024 / 1024, 2) . ' MB' . PHP_EOL;
   for ($i = 1; $i < 800000; $i++) {
      yield $i;
      // let us do profiling, so we measure the memory usage
      if (($i % 200000) == 0) {
         // get memory usage in megabytes
         echo round(memory_get_usage() / 1024 / 1024, 2) . ' MB'. PHP_EOL;
      }
   }
}
$myValues = getValues(); // no action taken until we loop over the values
foreach ($myValues as $value) {} // start generating values here

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

0.34 MB
0.34 MB
0.34 MB
0.34 MB

这并不意味着您要从 return 表达式迁移到 yield,但是如果您在应用程序中构建巨大的数组会导致服务器上的内存问题,那么 yield 适合您的情况。


3.什么是yield选项

yield有很多选项,我将重点介绍其中的几个:

第一种。使用 yield,您还可以使用 return:

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

第二种。返回键值对:

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

查看更多信息:

https://www.php.net/manual/en/language.generators.syntax.php


4.结论

这个话题的主要原因是在内存方面明确了 yield 和 return 之间的区别,展示了一些例子,因为我发现这对于任何开发人员来说都非常重要。


5. 参考文献

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


转:

https://medium.com/tech-tajawal/use-memory-gently-with-yield-in-php-7e62e2480b8d

相关文章