swoole之協程channel元素個數

前言

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

相關文章
相關標籤/搜索