美文网首页
swoole协程channel元素个数

swoole协程channel元素个数

作者: traveller227 | 来源:发表于2019-01-14 18:22 被阅读38次

    channel用于进程内跨协程通讯,按照角色分为生产协程和消费协程。
    生产协程,在channel已满时,会被挂起;
    消费协程,在channel为空是,也会被挂起。

    看例子:

    <?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数据不足,消费协程会挂起,程序无法正常退出。

    准确设置channel元素个数,是很重要的事。
    实践中,有些场景无法预测channel元素个数(例如请求第三方接口,如果有数据则push到channel,无数据则不push),那有什么解决办法嘛?
    有!

    • 可以少设置一些消费次数,保证生产者协程不挂起即可
    • 在php的register_shutdown_function()函数中,去实现未完成的消费者功能
    <?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());
            }
        });
    });
    

    这个办法能解决问题,但是显然不是那么优雅

    • 消费者函数要重复写一遍,由于swoole协程的语法,无法复用
    • 这个问题,应该在swoole协程层面来处理,在register_shutdown_function()中处理,也只是临时解决办法

    结尾
    swoole协程的push/pop机制,决定了需要设置一个合理的channel元素个数。
    实践中某些场景,又无法准确评估这个值,只能用临时办法解决,希望swoole能提供更优雅的解决方式。

    相关文章

      网友评论

          本文标题:swoole协程channel元素个数

          本文链接:https://www.haomeiwen.com/subject/gqpjdqtx.html