你好, 我是程序猿零壹。******
******今天要給大家?guī)韕hp中yield的用法。對于yield,我相信大部分的人依舊是不會用,甚至不知道什么是yield。那么今天這篇文章就是來告訴大家有關(guān)于yield的一些用法,以及如何用yield來解決我們在php中遇到的問題。希望對大家有所幫助。******
******不知道大家有沒有碰到過這樣的問題,使用excel導(dǎo)入大量數(shù)據(jù)的時候會失敗,并且提示以下錯誤信息:******
Fatal Error: Allowed memory size of xxxxxx bytes
******這個是因?yàn)樵趐hp程序中,是將變量存儲在內(nèi)存中。當(dāng)從excel中要導(dǎo)入的數(shù)據(jù)量過大的時候,會出現(xiàn)內(nèi)存不足的錯誤提示。
要解決這個問題,可以通過修改php中對于最大運(yùn)行內(nèi)存的設(shè)置:
ini_set('memory_limit', '200M');
但是這么做不能從根本上解決問題,當(dāng)我們需要讀取5g甚至更大文件的時候,我們的運(yùn)行內(nèi)存可能就吃不消了。
幸好,在php5.5之后提新增了生成器(Generators)特性,用于簡化實(shí)現(xiàn)迭代器接口(iterator)創(chuàng)建簡單的迭代器的復(fù)雜性。通過生成器,我們可以輕松的使用 foreach 迭代一系列的數(shù)據(jù),而不需要事先在內(nèi)存中構(gòu)建要被迭代的對象,大大減少了內(nèi)存的開銷。
這樣說可能比較抽象,不易于理解。所以我們先拋開有關(guān)于生成器的概念,先來看一個簡單的例子。
$arr = range(1,100)
這里用到了range函數(shù),它的作用是在內(nèi)存中生成一個數(shù)組包含每個在指定范圍內(nèi)的值,并返回該數(shù)組。
如果我們自己來實(shí)現(xiàn)這樣一個數(shù)組,應(yīng)該怎么做呢?我們來看下面的代碼:
function xrange($start,$end,$step=1){
$data = [];
for($i=$start;$i<$end,$i += $step) {
$data[] = $i;
}
return $data;
}
$start = memory_get_usage();
$data = xrange(1,1000);
foreach ($data as $value) {
echo $value.PHP_EOL;
}
$end = memory_get_usage();
echo "start:".$start.PHP_EOL;
echo "end:".$end.PHP_EOL;
echo "used:".($end - $start);
我們來看下start為1,end 分別為 10,100,1000,10000的情況下的內(nèi)存消耗情況分別是怎么樣的:
xrange(1,10); // used = 3480 0.0033187866210938MB
xrange(1,100); // used = 30168 0.028770446777344MB
xrange(1,1000); // used = 285144 0.27193450927734MB
xrange(1,10000); // used = 2957784 2.8207626342773MB
不難看出,隨著$end的增大,所占用的內(nèi)存也越來越大。
接下來我們來改造下xrange函數(shù):
function xrange($start,$end,$step=1){
for($i=$start;$i<$end,$i += $step) {
yield $i;
}
}
我們刪除了數(shù)組data,并且也刪除了返回值,而在foreach的循環(huán)體里,在i前面添加關(guān)鍵字:yield。****
我們來看下改造之后的內(nèi)存消耗:
xrange(1,10); // used = 256 0.000244140625MB
xrange(1,100); // used = 256 0.000244140625MB
xrange(1,1000); // used = 256 0.000244140625MB
xrange(1,10000); // used = 256 0.000244140625MB
Wow,這個結(jié)果令人驚訝。我們奇跡的發(fā)現(xiàn)了,內(nèi)存消耗并沒有隨著$end的增大而增大,甚至是完全一樣。
我們來還原一下代碼的執(zhí)行過程:
******首先調(diào)用xrange函數(shù),傳參$end=10,但是for循環(huán)了一次然后停止了,并且告訴foreach第一次循環(huán)可以用的值。
-
******foreach開始對$data循環(huán),并使用for給的一個值執(zhí)行輸出。******
-
******foreach開始第二次循環(huán),它向for循環(huán)又請求了一次******
-
******for循環(huán)又執(zhí)行了一次,并將新的值告訴foreach
-
******foreach拿到第二個值,開始輸出。
******所以,整個代碼執(zhí)行中,始終只有一個記錄值參與循環(huán),內(nèi)存中也只有一條信息。
無論開始傳入按的$end有多大,由于不會立即生成所有結(jié)果集,所以內(nèi)存始終是一條循環(huán)的值,也就不會占用太大的內(nèi)存了。
******看到這里,你是不是想說,“就這?”。生成器的用處當(dāng)然不止這一些,還有其他的用武之地,比如協(xié)程。只不過因?yàn)楸救瞬攀鑼W(xué)淺,只能跟大家分享這么多了。大家感興趣的話,可以看下鳥哥關(guān)于在php中使用協(xié)程實(shí)現(xiàn)多任務(wù)調(diào)度的文章。
好了,今天就到這里,如果大家覺得有用的話,不要忘記點(diǎn)贊收藏哦~
-
程序
+關(guān)注
關(guān)注
117文章
3826瀏覽量
82996 -
生成器
+關(guān)注
關(guān)注
7文章
322瀏覽量
21901 -
PHP
+關(guān)注
關(guān)注
0文章
454瀏覽量
27543
發(fā)布評論請先 登錄
python生成器
漢語句子聯(lián)想生成器
python生成器是什么
TSMaster報文發(fā)送的信號生成器操作說明

評論