前言

php业务场景中,我们在多个进程之间的通信一般会通过redis内存缓存来达到效果 在协程间的通信,我们可以使用Channel来实现,在类比php多进程处理的时候,可以将Channel类比成redis的队列

Channel特点

与容量有关
如果channel未满,push不阻塞,如果已满,push让出控制流;
如果channel为空,pop让出控制流

demo代码

<?php
/**
 * 生产者:3个协程序
 *
 * 生产者:设置一个容量为15的channel
 */
$chan = new \Swoole\Coroutine\Channel(15);
function t4(\Swoole\Coroutine\Channel $chan) {
    Co::sleep(0.005);    #1 (让出控制流,刮起)
    $chan->push([__METHOD__=>__LINE__]);    #2
}

function t5(\Swoole\Coroutine\Channel $chan) {
    Co::sleep(0.005);    #3  (让出控制流,刮起)
    $chan->push([__METHOD__=>__LINE__]);    #4
}

function t6(\Swoole\Coroutine\Channel $chan) {
    Co::sleep(0.005);    #5  (让出控制流,刮起)
    $chan->push([__METHOD__=>__LINE__]);    #6
}
// 启动 3 个生产者协程
go("t4", $chan);
go("t5", $chan);
go("t6", $chan);

/**
 * 消费者:cousume协程:c1
 */
go(function() use($chan) {
    // chan元素个数
    $chanNum = 3;
    // chan有数据时
    while($chanNum>0) {    #7
        $item = $chan->pop();    #8
        var_dump($item);    #9
        $chanNum --;
    }
});

代码分析

角色说明

  • 3个生产者协程 (t4、t5、t6)
  • 1个消费者协程 (c1)

代码执行

  • t4 协程中#1,遇到 Co::sleep() ,让出控制流,挂起(#3、#5 同理)。
  • c1开始执行,while循环为真,执行 channel::pop()
  • 可能情况:
    #8中可能情况1:channel为空,c1让出控制流,挂起;
    #8中可能情况2:channel非空,pop弹出数据,while循环继续
  • 如果 while 为假,则结束,c1 流量结束
  • 如果 while 为真,则进入 channel::pop() 流程,t4 恢复执行(t4、t5、t6 的 sleep 时间相同,因此都有可能线恢复执行,但是统一时刻只有有一个恢复,这里以 t4 为例)。此时 t4 的 channel 写入数据,那么 channel 非空。此时控制流发生变化,消费者协程 c1 恢复执行。c1 协程运行直到让出控制流或者结束。