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

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

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

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

[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秒??3d

如今运行脚本:code

[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官方群的高人指点,给出了正确的执行路径以下图(数字从小到大是执行顺序):blog

 

由于设置的capacity=1,致使第二次的push未成功,须要先pop方能继续下去。ci

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

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

从第三次数据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的做用是限制管道写入的长度。