zoukankan      html  css  js  c++  java
  • swoole的协程channel容量理解和实例说明

    首先翻到官网https://wiki.swoole.com/#/coroutine/channel

    有关channel:通道,用于协程间通讯,支持多生产者协程和多消费者协程。底层自动实现了协程的切换和调度。

    其构造方法:SwooleCoroutineChannel->__construct(int $capacity = 1),有个capacity的容量参数,一开始并不理解, 敲点代码尝试下,理解起来容易许多。

    [root@guangzhou coroutine]# cat coroutine_channel.php
    <?php
    #开启一键协程
    Co::set(['hook_flags'=> SWOOLE_HOOK_ALL]);
    
    Co
    un(function(){
        // 设置一个容量为1的通道
        $chan = new SwooleCoroutineChannel(1);
    
        SwooleCoroutine::create(function () use ($chan) {
            for($i = 0; $i < 6; $i++) {
            $chan->push( date('H:i:s') .  " 数据 i:" . $i . "
    ");
                echo date('H:i:s') . " 第{$i}次塞数据时间
    ";
            }
        });
    
        SwooleCoroutine::create(function () use ($chan) {
            while(1) {
                $data = $chan->pop();
                if($data){
                   echo  date('H:i:s') . " 取数据时间
    ";
                   echo $data . "
    ";
                   Co::sleep(2);
                }else{
                   break;
                }
            }
        });
    });
    //看到这段代码,你认为他的输出情况是怎样,先自己思考下!!

    上面脚本运行后每次pop后获取通道数据后休眠2秒,是协程模式,可能也会想当然认为每次取到数据的间隔应该是2秒??

    现在运行脚本:

    [root@guangzhou coroutine]# php coroutine_channel.php
    06:55:32 第0次塞数据时间
    06:55:32 第1次塞数据时间
    06:55:32 取数据时间
    06:55:32 数据 i:0
    
    06:55:34 第2次塞数据时间
    06:55:34 取数据时间
    06:55:32 数据 i:1
    
    06:55:36 第3次塞数据时间
    06:55:36 取数据时间
    06:55:32 数据 i:2
    
    06:55:38 第4次塞数据时间
    06:55:38 取数据时间
    06:55:34 数据 i:3
    
    06:55:40 第5次塞数据时间
    06:55:40 取数据时间
    06:55:36 数据 i:4
    
    06:55:42 取数据时间
    06:55:38 数据 i:5

    有没有发现前三次取数据时间点都是2秒的,第四次的数据一下子到了4秒。

    经过swoole官方群的高人指点,给出了正确的执行路径如下图(数字从小到大是执行顺序):

    因为设置的capacity=1,导致第二次的push未成功,需要先pop方能继续下去。

    第一次pop后,回到第三次push循环,程序判断管道已满这时将处理第一次pop的数据,又开始第四次push循环,程序判断管道又满了,pop第二次push的数据。

    到目前为止前三次push的数据并未进入到sleep这里,导致后续打印第一次pop数据时,塞数据时间点比取数据时间点被推后了。

    从第三次数据pop后的数据都要经历push失败->echo+sleep->pop上一次的,这里就会有休眠2秒的时间加上pop上次时间就是4秒了。

    这里有点绕,需要多思考并动手实践。

    修改capacity=10,并push循环7次,运行程序:

    [root@guangzhou coroutine]# cat coroutine_channel.php
    <?php
    #开启一键协程
    Co::set(['hook_flags'=> SWOOLE_HOOK_ALL]);
    
    Co
    un(function(){
        // 设置一个容量为1的通道
        $chan = new SwooleCoroutineChannel(10);
    
        SwooleCoroutine::create(function () use ($chan) {
            for($i = 0; $i < 7; $i++) {
            $chan->push( date('H:i:s') .  " 数据 i:" . $i . "
    ");
                echo date('H:i:s') . " 第{$i}次塞数据时间
    ";
            }
        });
    
        SwooleCoroutine::create(function () use ($chan) {
            while(1) {
                $data = $chan->pop();
                if($data){
                   echo  date('H:i:s') . " 取数据时间
    ";
                   echo $data . "
    ";
                   Co::sleep(2);
                }else{
                   break;
                }
            }
        });
    });

    执行脚本:

    [root@guangzhou coroutine]# php coroutine_channel.php
    07:29:22 第0次塞数据时间
    07:29:22 第1次塞数据时间
    07:29:22 第2次塞数据时间
    07:29:22 第3次塞数据时间
    07:29:22 第4次塞数据时间
    07:29:22 第5次塞数据时间
    07:29:22 第6次塞数据时间
    07:29:22 取数据时间
    07:29:22 数据 i:0
    
    07:29:24 取数据时间
    07:29:22 数据 i:1
    
    07:29:26 取数据时间
    07:29:22 数据 i:2
    
    07:29:28 取数据时间
    07:29:22 数据 i:3
    
    07:29:30 取数据时间
    07:29:22 数据 i:4
    
    07:29:32 取数据时间
    07:29:22 数据 i:5
    
    07:29:34 取数据时间
    07:29:22 数据 i:6

    发现所有 i:xxx 的时间点几乎一致。

    结论即是capacity的作用是限制管道写入的长度,如果超出写入长度限制则会写入失败,等数据pop后数据量少于capacity等数值才能push管道写入成功。

  • 相关阅读:
    sql 删除
    sql 修改
    sql 新增
    sql UNION 和UNION ALL 数据连接查询
    WITH AS 子查询部分【mysql5.7及以下不支持,mysql8.0及sqlserver支持】
    sql 高级开窗函数row_number() over()和row_number() over(partition by)【mysql5.7及以下不支持,mysql8.0及sqlserver支持】
    sql 查询去重
    sql 常用聚合函数介绍
    sql 分组(group by)
    NPM 私有仓库搭建
  • 原文地址:https://www.cnblogs.com/wscsq789/p/13743532.html
Copyright © 2011-2022 走看看