swoole协程之channel

前言

经过swoole协程入门,了解到协程的基本写法。
更准确一点,是独立、无执行顺序的任务。
那有依赖关系或者执行顺序有关的任务怎么办呢?
靠channel了!php

Channel特色

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

看例子:depend_co.php

<?php
// 设置一个容量为50的channel
$chan = new \Swoole\Coroutine\Channel(50);
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
}
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描述)
#1 t4遇到Co::sleep,让出控制流,挂起
#3 t5,相似于t4,挂起
#5 t6,相似于t4,挂起
#7 c1开始执行,while循环为真,执行channel::pop()
#8 可能状况:channel为空,c1让出控制流,挂起
#8 可能状况:channel非空,pop弹出数据,while循环继续
若是while循环为假,c1执行结束
若是while循环为真,进入channel::pop()流程
...5ms后...
t4恢复执行(t4/t5/t6 sleep时间相同,所以都有可能先恢复执行,但同时只能有一个恢复,为描述简单以t4为例)
#2 t4写入channel数据,此时channel非空
#8 若是有消费者协程,控制流发生变化,消费者协程c1恢复执行(思考:若是c1的while循环为假已经结束,会发生什么呢?)
c1协程运行直到让出控制流或者结束;
控制流回到t4协程,t4协程没有后续代码,执行结束;(问题:控制流有可能回到其余协程t5/t6嘛?仍是必定会回到t4协程)
t5(t6)恢复执行,流程相似于t4的执行流程swoole

注意事项

channel的容量很重要,太小的容量致使生产者自动让出控制流而不能执行;
消费者,须要判断生产者个数,来肯定循环次数或循环结束边界,若是判断错误(过小,致使channel数据未消费;太大,消费者会让出控制流),会带来意外的结果。code

总结

回到文章的开头,好像咱们是想介绍有依赖关系、调用顺序的任务怎么写?
你确定已经猜到了,那就是先导任务放在生产者协程,后续任务放在消费者协程
经过channel的机制,保障任务的前后执行顺序协程

channel解决了协程间通讯的问题,同时也提供了一种任务调度的方式。get

相关文章
相关标签/搜索