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

相关文章
相关标签/搜索