前言
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 协程运行直到让出控制流或者结束。