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

評(píng)論