php 5.5 中最重要的特性之一就是對協程( coroutine )和生成器( generator )的支援。生成器的特性已經由官方文件和許多博文(比如這一篇和這一篇)講解得很充分了。另一方面,協程受到的關注則較少。這是因為協程的功能相較而言更加強大,但卻難以講解。
本文會使用協程實現乙個任務排程器,以此幫助你理解協程的概念和用法。我會先用幾個段落做一些介紹。如果你覺得你已經對生成器和協程的基本概念掌握得很牢固了,那麼你可以直接跳至「多工協作」這一段開始閱讀。
生成器背後最原始的想法就是乙個函式不僅僅返回一次資料,而是能夠返回一系列的資料,並且這些資料是挨個返回的。也可以理解為,生成器使你能更方便地實現迭代器。xrange()
函式就是乙個生成器的簡單例子:
function
xrange
($start, $end, $step = 1)
}foreach (xrange(1, 1000000) as $num)
上例中的xrange()
函式與內建函式range()
函式的功能相同。唯一的區別在於range()
會返回乙個包含了一百萬個數字的陣列,而xrange()
則返回乙個可以吐出這些數字的迭代器,不會去老實地計算出乙個包含所有數字的陣列。
這樣做的好處是顯而易見的。它使得你可以處理超大規模的資料,而無需一次性將它們載入記憶體。你甚至可以處理無窮無盡的資料流。
當然並不是只有生成器能做到這一點,你也可以通過實現乙個iterator
介面來完成同樣的工作。生成器只是更加方便,避免你為了生成乙個迭代器而不得不去實現該介面的五個不同方法。
要從對生成器的理解過度到協程的概念,理解它們內部的工作方式是非常重要的:生成器是可中斷的函式,而yield
語句則構成了這些中斷點。
接著剛才的例子,當你呼叫xrange(1, 1000000)
時,實際上xrange()
沒有執行任何**。取而代之地, php 僅返回了乙個generator
類的例項,它實現了iterator
介面:
$range = xrange(1, 1000000);
var_dump($range); // object(generator)#1
var_dump($range instanceof iterator); // bool(true)
只有當你呼叫 iterator 介面相關的方法時**才會執行。例如,你執行$range->rewind()
時,xrange()
函式中的**就會執行,直到流程中的第一條yield
語句。如此一來,就意味著$i = $start
和yield $i
被執行了。任何傳遞給yield
語句的資料都能通過$range->current()
來獲取。
你需要呼叫$range->next()
方法來繼續執行生成器中的**。這樣它就會繼續執行下去,直到下一條yield
語句。所以只要連續地呼叫->next()
和->current()
方法,你就可以從生成器中獲取到所有的返回值,直至最終不再遇到yield
語句。對於xrange()
函式來說,就是$i
超出$end
的時候。如此一來,流程會繼續執行完剩餘的**,直至函式的結尾。若此時呼叫->valid()
方法則會返回 false ,這個迭代過程就結束了。
相對於上述功能,協程最主要的一點就是加入了向生成器中傳送資料的能力。這使得從生成器到呼叫者的單向資料流,變成了兩者彼此往來的資料通路。
將資料傳遞給協程的方法是呼叫->send()
方法,而不是->next()
。下面的這個logger()
的例子展示了它是如何工作的:
function
logger
($filename)
}$logger = logger(__dir__ . '/log');
$logger->send('foo');
$logger->send('bar');
如你所見,在這裡yield
沒有被用作乙個語句,而是作為乙個表示式,也是就說它有乙個返回值。這個返回值是通過->send()
語句傳過來的。此例中yield
會先返回 'foo' 再返回 'bar'。 吊炸天的 PHP 7 ,你值得擁有
2015年的夏天,雖然來得不算火熱,但是在網際網路技術的夏天,比任何一年都更為火熱。剛剛才結束了 5 月底的網易 支付寶 攜程以及多家雲儲存廠商的接連故障的壞訊息,6月上旬則迎來了程式語言界兩大好訊息,第一件是 swift 2.0 發布以及開源,另一件是 php 7 alpha 版正式發布。這兩件大...
實習第八天 三款炫酷的動畫推薦
最近突然心血來潮,對一些loading感興趣,loading這玩意說重要也重要,說不重要也不重要,因為這是乙個提公升你產品體驗的乙個細節,如果loading做的好,對於一些耗時需要使用者等待的頁面來說會轉移使用者注意力,不會顯得那麼煩躁,所以你可以看到市面上各種各樣好玩的loading動畫,那麼這篇...