Understanding PHP Generators(譯)

PHP Generators

Understanding PHP Generators

為什么需要談?wù)揋enerators,作為互聯(lián)網(wǎng)應(yīng)有,更快的速度意味著更好的用戶體驗(yàn),而Generators則是php中解決速度和內(nèi)存的殺手锏

原文

代碼

What are PHP Generators?

在php5.5中加入,generators解決了在一個(gè)loop中不需要在內(nèi)存中構(gòu)建整個(gè)數(shù)組的問(wèn)題,可能這么說(shuō)還不是很明了

talk is cheap, show me the code

我們來(lái)看下一段代碼,保存為文件generator.php

<?php

function getRange ($max = 10) {
    $array = [];

    for ($i = 1; $i < $max; $i++) {
        $array[] = $i;
    }

    return $array;
}

foreach (getRange(15) as $range) {
    echo "Dataset {$range} <br>";
}

我們可以通過(guò)命令快速啟動(dòng)以個(gè)server

php -S localhost:8000

如果我們?cè)L問(wèn)http://localhost:8000/generator.php我們會(huì)看到下面

Dataset 1 
Dataset 2 
Dataset 3 
Dataset 4 
Dataset 5 
Dataset 6 
Dataset 7 
Dataset 8 
Dataset 9 
Dataset 10 
Dataset 11 
Dataset 12 
Dataset 13 
Dataset 14 

代碼很容易理解,也沒(méi)什么問(wèn)題,但是如果我們改動(dòng)下代碼:

<?php

foreach (getRange(PHP_INT_MAX) as $range) {
    echo "Dataset {$range} <br>";
}

此時(shí)最大數(shù)變?yōu)榱?strong>PHP_INT_MAX,再次運(yùn)行就會(huì)出現(xiàn)下面的錯(cuò)誤:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 134217736 bytes) in /private/tmp/php-generator/generator.php on line 7

超過(guò)最大內(nèi)存了,此時(shí)一個(gè)可能的解決方案是修改php.ini 然后增加memory_limit。但是這個(gè)真能解決問(wèn)題嗎,我們是否真的希望一個(gè)腳本耗盡了我們的內(nèi)存,顯然是no!

Using Generators

我們還是實(shí)現(xiàn)同樣的功能,這次我們創(chuàng)建一個(gè)generator函數(shù)

<?php

function getRange ($max = 10) {
    for ($i = 1; $i < $max; $i++) {
        yield $i;
    }
}

foreach (getRange(PHP_INT_MAX) as $range) {
    echo "Dataset {$range} <br>";
}

分析這次的getRange函數(shù),這次我們只是在loop中yield值,yield類似于return,不同之處在于yield只有在被返回的值需要的時(shí)候才會(huì)產(chǎn)生這個(gè)值,不會(huì)讓整個(gè)返回集合都在內(nèi)存中

此時(shí)我們?cè)俅卧L問(wèn)http://localhost:8000/generator.php,只要給瀏覽器足夠的時(shí)間,所有的數(shù)據(jù)都會(huì)返回

Why Do This?

我們的目標(biāo)是提升速度,但是內(nèi)存不增加。很多時(shí)候,我們?cè)谔幚韑og文件的時(shí)候,經(jīng)常會(huì)遇到內(nèi)存耗盡的情況,使用generator就能很好的解決

Returning Keys

除了返回簡(jiǎn)單的值,我們還能返回鍵值對(duì)

<?php

function getRange ($max = 10) {
    for ($i = 1; $i < $max; $i++) {
        $value = $i * mt_rand();

        yield $i => $value;
    }
}
foreach (getRange(PHP_INT_MAX) as $range => $value) {
    echo "Dataset {$range} has {$value} value<br>";
}

Sending Values to Generator

我們除了可以從generators中讀數(shù)據(jù),還能往里面寫數(shù)據(jù)

<?php

function getRange ($max = 10) {
    for ($i = 1; $i < $max; $i++) {
        $injected = yield $i;

        if ($injected === 'stop') return;
    }
}
$generator = getRange(PHP_INT_MAX);

foreach ($generator as $range) {
    if ($range === 10000) {
        $generator->send('stop');
    }

    echo "Dataset {$range} <br>";
}

注意: 在generators中使用return,將會(huì)退出generator

Don't Misuse Generators

Generators用來(lái)高效使用內(nèi)存,但是使用Generators并不意味著不會(huì)出現(xiàn)內(nèi)存耗盡的情況,如果錯(cuò)誤使用的話,也會(huì)遇到同樣的問(wèn)題。

Conclusion

Generators給我們提供了無(wú)法拒絕的性能提升。大多數(shù)時(shí)候,我們不需要高性能的服務(wù)器來(lái)解決問(wèn)題,需要的這是我們重構(gòu)下代碼。Generators非常棒,我們應(yīng)該多使用它。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容