1. 程式人生 > >在 PHP 中使用 `yield` 來做記憶體優化

在 PHP 中使用 `yield` 來做記憶體優化

你有沒有想過 "在 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