channel用於進程內跨協程通信,按照角色分爲生產協程和消費協程。
生產協程,在channel已滿時,會被掛起;
消費協程,在channel爲空是,也會被掛起。php
<?php $chan = new \Swoole\Coroutine\Channel(50); function t4(\Swoole\Coroutine\Channel $chan) { Co::sleep(0.005); $chan->push([__METHOD__ => __LINE__]); } function t5(\Swoole\Coroutine\Channel $chan) { Co::sleep(0.005); $chan->push([__METHOD__ => __LINE__]); } go("t4", $chan); go("t5", $chan); go(function () use ($chan) { // chan元素個數 $chanNum = 1; while ($chanNum > 0) { $item = $chan->pop(); var_dump($item); $chanNum--; } });
上面的例子,若是賦值$chanNum=1,會致使channel中有數據未被消費;
若是賦值$chanNum=3,因爲channel數據不足,消費協程會掛起,程序沒法正常退出。swoole
準確設置channel元素個數,是很重要的事。
實踐中,有些場景沒法預測channel元素個數(例如請求第三方接口,若是有數據則push到channel,無數據則不push),那有什麼解決辦法嘛?
有!函數
保證生產者協程不掛起的前提下,在php的register_shutdown_function()函數中,去實現未完成的消費者功能code
<?php register_shutdown_function(function() use ($chan) { go(function()use($chan){ $queue_num = $chan->stats()["queue_num"]; for($i=0;$i<$queue_num;$i++) { var_dump($chan->pop()); } }); });
這個辦法能解決問題,可是顯然不是那麼優雅,在register_shutdown_function()中處理,也只是臨時解決辦法協程
協程channel的push/pop機制,決定了須要設置一個合理的channel元素個數。
實踐中某些場景,又沒法準確評估這個值,只能用臨時辦法解決,但願swoole能提供更優雅的解決方式。接口
因爲協程的非順序化處理,channel元素個數的評估是沒法實現的。
基於此,經過約定來規避此類問題:
每一個生產者協程的結果須要push到channel裏,生產者個數=channel元素個數;
消費者協程只有一個,且出如今全部的生產者協程後,能夠正確讀取到生產者協程個數
讀取生產者協程個數Co::stats()
或者Coroutine::listCoroutines
進程
Refer:
swoole的channel之waitgroup實現get