你好, 我是程序猿零壹。******
******今天要給大家帶來php中yield的用法。對于yield,我相信大部分的人依舊是不會用,甚至不知道什么是yield。那么今天這篇文章就是來告訴大家有關于yield的一些用法,以及如何用yield來解決我們在php中遇到的問題。希望對大家有所幫助。******
******不知道大家有沒有碰到過這樣的問題,使用excel導入大量數據的時候會失敗,并且提示以下錯誤信息:******
Fatal Error: Allowed memory size of xxxxxx bytes
******這個是因為在php程序中,是將變量存儲在內存中。當從excel中要導入的數據量過大的時候,會出現內存不足的錯誤提示。
要解決這個問題,可以通過修改php中對于最大運行內存的設置:
ini_set('memory_limit', '200M');
但是這么做不能從根本上解決問題,當我們需要讀取5g甚至更大文件的時候,我們的運行內存可能就吃不消了。
幸好,在php5.5之后提新增了生成器(Generators)特性,用于簡化實現迭代器接口(iterator)創建簡單的迭代器的復雜性。通過生成器,我們可以輕松的使用 foreach 迭代一系列的數據,而不需要事先在內存中構建要被迭代的對象,大大減少了內存的開銷。
這樣說可能比較抽象,不易于理解。所以我們先拋開有關于生成器的概念,先來看一個簡單的例子。
$arr = range(1,100)
這里用到了range函數,它的作用是在內存中生成一個數組包含每個在指定范圍內的值,并返回該數組。
如果我們自己來實現這樣一個數組,應該怎么做呢?我們來看下面的代碼:
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的情況下的內存消耗情況分別是怎么樣的:
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的增大,所占用的內存也越來越大。
接下來我們來改造下xrange函數:
function xrange($start,$end,$step=1){
for($i=$start;$i<$end,$i += $step) {
yield $i;
}
}
我們刪除了數組data,并且也刪除了返回值,而在foreach的循環體里,在i前面添加關鍵字:yield。****
我們來看下改造之后的內存消耗:
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,這個結果令人驚訝。我們奇跡的發現了,內存消耗并沒有隨著$end的增大而增大,甚至是完全一樣。
我們來還原一下代碼的執行過程:
******首先調用xrange函數,傳參$end=10,但是for循環了一次然后停止了,并且告訴foreach第一次循環可以用的值。
-
******foreach開始對$data循環,并使用for給的一個值執行輸出。******
-
******foreach開始第二次循環,它向for循環又請求了一次******
-
******for循環又執行了一次,并將新的值告訴foreach
-
******foreach拿到第二個值,開始輸出。
******所以,整個代碼執行中,始終只有一個記錄值參與循環,內存中也只有一條信息。
無論開始傳入按的$end有多大,由于不會立即生成所有結果集,所以內存始終是一條循環的值,也就不會占用太大的內存了。
******看到這里,你是不是想說,“就這?”。生成器的用處當然不止這一些,還有其他的用武之地,比如協程。只不過因為本人才疏學淺,只能跟大家分享這么多了。大家感興趣的話,可以看下鳥哥關于在php中使用協程實現多任務調度的文章。
好了,今天就到這里,如果大家覺得有用的話,不要忘記點贊收藏哦~
-
程序
+關注
關注
116文章
3775瀏覽量
80843 -
生成器
+關注
關注
7文章
313瀏覽量
20976 -
PHP
+關注
關注
0文章
452瀏覽量
26647
發布評論請先 登錄
相關推薦
評論