swoole的协程channel容量理解和实例说明

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

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

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

[root@guangzhou coroutine]# cat coroutine_channel.php
<?php
#开启一键协程
Co::set(['hook_flags'=> SWOOLE_HOOK_ALL]);

Co\run(function(){
    // 设置一个容量为1的通道
    $chan = new Swoole\Coroutine\Channel(1);

    Swoole\Coroutine::create(function () use ($chan) {
        for($i = 0; $i < 6; $i++) {
        $chan->push( date('H:i:s') .  " 数据 i:" . $i . "\n");
            echo date('H:i:s') . " 第{$i}次塞数据时间\n";
        }
    });

    Swoole\Coroutine::create(function () use ($chan) {
        while(1) {
            $data = $chan->pop();
            if($data){
               echo  date('H:i:s') . " 取数据时间\n";
               echo $data . "\n";
               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\run(function(){
    // 设置一个容量为1的通道
    $chan = new Swoole\Coroutine\Channel(10);

    Swoole\Coroutine::create(function () use ($chan) {
        for($i = 0; $i < 7; $i++) {
        $chan->push( date('H:i:s') .  " 数据 i:" . $i . "\n");
            echo date('H:i:s') . " 第{$i}次塞数据时间\n";
        }
    });

    Swoole\Coroutine::create(function () use ($chan) {
        while(1) {
            $data = $chan->pop();
            if($data){
               echo  date('H:i:s') . " 取数据时间\n";
               echo $data . "\n";
               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管道写入成功。

posted @ 2020-09-28 15:33  潮起潮落中看星辰大海  阅读(1009)  评论(0编辑  收藏  举报