× 警告!旧版文档已经暂停维护,请查看新版文档。点击前往新版文档

协程执行流程

协程执行流程遵循以下原则:

  • 协程没有IO等待 正常执行PHP代码,不会产生执行流程切换
  • 协程遇到IO等待 立即将控制权切,待IO完成后,重新将执行流切回原来协程切出的点
  • 协程并行协程依次执行,同上一个逻辑
  • 协程嵌套执行流程由外向内逐层进入,直到发生IO,然后切到外层协程,父协程不会等待子协程结束

IO等待

  • 正常执行PHP代码,不会产生执行流程切换

IO操作的协程,相当于一次PHP函数调用

echo "main start\n";
go(function () {
    echo "coro ".co::getcid()." start\n";
});
echo "end\n";
/*
main start
coro 1 start
end
*/

IO等待

  • 立即将控制权切,待IO完成后,重新将执行流切回原来协程切出的点
echo "main start\n";
go(function () {
    echo "coro ".co::getcid()." start\n";
    co::sleep(.1); //switch at this point
    echo "coro ".co::getcid()." end\n";
});
echo "end\n";
/*
main start
coro 1 start
end
coro 1 end
*/

协程并行

协程依次执行,同上一个逻辑

echo "main start\n";
go(function () {
    echo "coro ".co::getcid()." start\n";
    co::sleep(.1);
    echo "coro ".co::getcid()." end\n";
});

echo "main flag\n";
go(function () {
    echo "coro ".co::getcid()." start\n";
    co::sleep(.1);
    echo "coro ".co::getcid()." end\n";
});

echo "end\n";
/*
main start
coro 1 start
main flag
coro 2 start
end
coro 1 end
coro 2 end
*/

协程嵌套

执行流程由外向内逐层进入,直到发生IO,然后切到外层协程,父协程不会等待子协程结束

echo "main start\n";
go(function () {
    echo "coro ".co::getcid()." start\n";
    go(function () {
        echo "coro ".co::getcid()." start\n";
        co::sleep(.1);
        echo "coro ".co::getcid()." end\n";
    });
    echo "coro ".co::getcid()." do not wait children coroutine\n";
    co::sleep(.2);
    echo "coro ".co::getcid()." end\n";
});
echo "end\n";
/*
main start
coro 1 start
coro 2 start
coro 1 do not wait children coroutine
end
coro 2 end
coro 1 end
*/
echo "main start\n";
go(function () {
    echo "coro ".co::getcid()." start\n";
    go(function () {
        echo "coro ".co::getcid()." start\n";
        co::sleep(.2);
        echo "coro ".co::getcid()." end\n";
    });
    echo "coro ".co::getcid()." do not wait children coroutine\n";
    co::sleep(.1);
    echo "coro ".co::getcid()." end\n";
});
echo "end\n";
/*
main start
coro 1 start
coro 2 start
coro 1 do not wait children coroutine
end
coro 1 end
coro 2 end
*/

  • sonly

    协程不是串行运行的么,不是基于一个线程的么?如此父协程为什么能不等子协程执行完就执行,这么一来不就变成并行运行了么?

  • 新用户(手机注册)

    楼上理解错误

  • slysjun

    不明白示例中的父协程为什么会等待内嵌的子协程执行完打印结果,整个程序才结束。不是说父协程不能等待子协程的结束吗?

  • jichengyang

    父协程是没等待字协程结束呀,上面的例子:子协程阻塞被挂起,但是不影响父协程的输出,父协程未等待子协程,而是当前php建立的进程在等待内嵌的子协程(用户线程)执行完打印结果

  • jichengyang

    协程并不是一定缩短代码的执行时间,我在测试的发现:1.没有io阻塞时,多个go运行切换,执行顺序是和正常的串行代码一样,但是消费的时间却比正常时间要高。2.有io阻塞时,时间也是比正常时间要高。 因此 我个人认为协程的使用要注重场景,然后得达到比较高的并发量了才应当使用它来开发业务 比如:云盘系统,大文件下载,1G的文件,我们可以把文件分成n份,n份文件对应n个协程去处理,那效率和时间自然没得说了 以上观点出自于个人,理解应该会有错误的地方

  • jichengyang

    就是说 好东西用在刀刃上 别来不来就协程 事半功倍

  • jichengyang

    上面写反了,难受 就是说 好东西用在刀刃上 别来不来就协程 事倍功半

  • Nick

    大家可以这么想:只要碰到IO阻塞,就跳出go函数,IO阻塞完成后就跳回go函数里,这样的话,上面的例子就很简单了

  • 七分宠溺  ლ

    sleep的时间哪个最先结束,就最先回到那一层继续执行