當前位置:
首頁 > 知識 > 關於PHP協程與阻塞的思考

關於PHP協程與阻塞的思考

進程、線程、協程

關於進程、線程、協程,有非常詳細和豐富的博客或者學習資源,我不在此做贅述,我大致在此介紹一下這幾個東西。

進程擁有自己獨立的堆和棧,既不共享堆,亦不共享棧,進程由操作系統調度。

線程擁有自己獨立的棧和共享的堆,共享堆,不共享棧,線程亦由操作系統調度(標準線程是的)。

協程和線程一樣共享堆,不共享棧,協程由程序員在協程的代碼里顯示調度。

PHP中的協程實現基礎 yield

yield的根本實現是生成器類,而迭代器類是迭代器介面的實現:

GeneratorimplementsIterator {publicmixed current (void)// 返回當前產生的值publicmixed key (void)// 返回當前產生的鍵publicvoidnext(void)// 生成器繼續執行publicvoidrewind (void)// 重置迭代器,如果迭代已經開始了,這裡會拋出一個異常。// renwind的執行將會導致第一個yield被執行, 並且忽略了他的返回值.publicmixed send ( mixed $value )// 向生成器中傳入一個值,並且當做 yield 表達式的結果,然後繼續執行生成器。如果當這個方法被調用時,生成器// 不在 yield 表達式,那麼在傳入值之前,它會先運行到第一個 yield 表達式。publicvoidthrow( Exception $exception )// 向生成器中拋入一個異常publicbool valid (void)// 檢查迭代器是否被關閉publicvoid__wakeup (void)// 序列化回調,拋出一個異常以表示生成器不能被序列化。}

以上解析可以參考PHP官方文檔。

http://php.net/manual/zh/clas...

以及鳥哥翻譯的這篇詳細文檔:

http://www.laruence.com/2015/...

我就以他實現的協程多任務調度為基礎做一下例子說明並說一下關於我在阻塞方面所做的一些思考。

自定義簡單定時執行任務示例:

(此例子必須依賴於以上鳥哥實現的協程調度代碼)

classtimer{private$start =;// 定時開始時間private$timer;// 間隔的時間差,單位秒private$value =;// 產生的結果值private$callback;// 非同步回調private$isEnd =false;// 當前定時器任務是否結束publicfunction__construct($timer,callable $callback){$this->start = time();$this->timer = $timer;$this->callback = $callback; }publicfunctionrun(){if($this->valid()) { $callback =$this->callback; $callback($this->value ++,$this);$this->start = time(); } }/** * 定時執行檢查 */publicfunctionvalid(){ $end = time();if($end -$this->start >=$this->timer) {returntrue; }else{returnfalse; } }publicfunctionsetEnd($isEnd){$this->isEnd = $isEnd; }publicfunctiongetEnd(){return$this->isEnd; }}/** * 模擬阻塞的協程1 * */functiontaskObject1(){ $timer =newtimer(1,function($value,timer $timer){if($value >=5) { $timer->setEnd(true); }echo

. A .$value; }); $tid = (yieldgetTaskId());while(true) {if($timer->getEnd() ==true) {break; }yield$timer->run(); }}/** * 模擬阻塞的協程2 * */functiontaskObject2(){ $timer =newtimer(2,function($value,timer $timer){if($value >=3) { $timer->setEnd(true); }echo

. B .$value; }); $tid = (yieldgetTaskId());while(true) {if($timer->getEnd() ==true) {break; }yield$timer->run(); }}$scheduler =newScheduler;$scheduler->newTask(taskObject1());$scheduler->newTask(taskObject2());$scheduler->run();

以上實現的是:

產生兩個任務,並行執行,並且給每個任務在執行的時候模擬幾秒鐘的阻塞;

讓協程切換的時候能順利切換,其中的任務阻塞不相互影響;

思考:

我為什麼要做以上這件事情呢?因為我發現協程實現雖然很強大也很有意思,能讓多任務並行,但是我在其中一個任務里調用系統函數 的時候,阻塞任務會阻止協程切換,其實從協程的實現原理上來書也是這麼回事。

那麼,我也就想模擬協程阻塞,但是不產生阻塞看是否可行。PHP本身只提供了生成器為協程調用提供了支撐,如果不依賴擴展,沒有提供多線程的程序實現方式,沒有java那麼強大,可以開子線程進行實現。

我印象中java的子線程是獨立執行且不會相互阻塞的,所以我在想,PHP既然可以實現類似於多線程這樣的機制,那麼能不能實現調用過程中非阻塞呢?

經過這樣一個實現和思考,一開始是陷入了一個誤區的,是由於PHP原生函數 阻塞造成的思維誤區,那就是認為要想真正實現非阻塞或者說實現非同步的話,是必須依賴於語言底層的。

後來,我想明白了一個道理,既然某個方法或者函數在執行過程中,會產生阻塞,那麼把當前這個方法換成自定義的,做成非阻塞(相對於整個協程調度來說)不就行了嗎?比如上面的定時執行我自己實現了一個。

而另一方面,協程調度本身的目的也是為了把任務執行過程切成盡量小片,從而快速切換執行,達到並行的目的。從這方面來看,協程應該也算是一種程序設計思想。

以下是一個程序切成盡量小片執行的例子:

// 一個簡單的例子

這個例子是把原本用 生成一個很大的整型數組的方式切換為分片執行,也就是說在遍歷的時候再去取到指定的值,從代碼上來看,內存消耗相對於之前來說就非常小了。

點擊展開全文

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 PHP技術大全 的精彩文章:

高並發下的下單功能設計
Uber醜聞不斷,被曝將問題車租給司機
VIM使用技巧及快捷操作
MySQL性能優化的最佳20 條經驗

TAG:PHP技術大全 |

您可能感興趣

阻塞IO、非阻塞IO和非同步IO
利用OpenSSL實現非阻塞通訊C++代碼
急性心梗患者PCI術中用阿替普酶,對預防微血管阻塞無效
5 個用 Python 編寫非阻塞 web 爬蟲的方法
MySQL Innodb 如何找出阻塞事務源頭 SQL
波士頓科學治療髂股靜脈阻塞性的VICI支架系統獲FDA批准
BMJ:慢性阻塞性肺病的三聯療法
阻塞性睡眠呼吸暫停的多學科診治,看最新指南的建議
針對慢性阻塞性肺疾病 的新型高效抗炎納米藥物的開發研究
白天嗜睡新葯!美國FDA批准Sunosi治療發作性睡病和阻塞性睡眠呼吸暫停相關白天過度嗜睡
科學家從位渦梯度的角度研究北極增暖對大氣阻塞的影響
同步阻塞 非同步阻塞 同步非阻塞 非同步非阻塞
美軍最大紅旗軍演進行中,全球定位系統GPS信號受阻塞
關於慢性阻塞性肺疾病的臨終治療
藥物+支架,全面開通阻塞的心臟血管
阜外研究:嚴重肺動脈高壓患者應注意篩查呼吸疾病,尤其是阻塞性睡眠呼吸暫停低通氣綜合征
The Lancet:中國有將近1億成年人飽受慢性阻塞性肺病的困擾!
肥胖打呼嚕嚴重,導致阻塞性睡眠呼吸暫停綜合症!
浪潮SDS,讓視頻分發無阻塞,播出更精彩
隨機數阻塞問題