首页 > 作文

Swoole4.4协程抢占式调度器详解

更新时间:2023-04-07 08:32:21 阅读: 评论:0

前言

swoole内核团队开设的专栏,会逐渐投入精力写文章介绍swoole的开发历程,实现原理,应用实践等,大家可以更好的交流,共同学习,建设php生态。

协程调度

去年swoole推出了4.0版本后,完整的支持php协程,我们可以基于协程实现csp编程,身边的开发者惊呼,原来php代码还可以这样写。swoole的协程默认是基于io调度,程序中有阻塞会自动让出当前协程,协程的各种优势我们不在这里展开讨论。如果是io密集型的场景,可以表现得很不错。但是对于cpu密集型的场景,会导致一些协程因为得不到cpu时间片被饿死。

抢占式调度

我们在今年年初就计划实现swoole的抢占式调度,以满足实现有些场景下的不均衡调度带来的问文艺部工作总结题。我们中间经历了几个版本,在这里和大家分享一下开发过程中的动机和解决办法。

我们目的是为了均衡调度每个协程的cpu时间,比如协程3需要比较长的执行时间,我们必须把协程3的cpu时间主动中断,而不依赖io事件,使得每个协程得到平均的执行时间。

起初,我们的想法是可以从php的循环中自动检测执行实践,若达到限制,可以自动让出当前协程。因为毕竟很少有人一马平川的写出占用很多cpu的代码,大都通过循环条件来控制。我们hook循环指令,每次执行循环指令的时候,都来检查协程的执行时间,我们很欣喜的得到了最初的版本。但是这样做比较hack,而且opcode经过opcache优化后,情况会变得有些复杂。

后来我们使用phpticks机制,也就是在php代码编译期间,注入ticks指令,可以执行相应的函数,我们可以在这些函数中检测处理协程的时间,达到抢占式的效果,但是这里有一个问题,phpdeclare(ticks=n)语法,只对当前脚本范围有效,也就是说项目稍微大点,require或者include进来的脚本,并不会自动注入ticks指令,这样swoole开发者几乎是无法接受的。我们也试图给php官方提一个pr,可以在扩展层设置一个全局默认的ticks,但是官方不愿意采纳我们的提交,因为官方觉得这个功能对性能损耗比较大,而且有可能在php8移除这个功能。其实经过实测这个性能损耗并不大,而且我们已经在生产环境验证,并取得了显著的效果,即可以让出某些cpu密集的逻辑部分,使得服务整个相应时间更加均衡。

下图是我们生产环境一个rpc接口的调用端统计数据对比,客户端等待超时时间为2s,超时则统计为错误。

左边一侧是没有抢占式调度,右侧是开了抢占式调度,可以发现,左侧总是会有偶尔超时情况,而经过优化之后,没有一个超时的请求,请求响应时间非常平滑,提升了服务的稳定性。

可以从上图看出,由于抢占式调度的加入,去除了请求耗时高的毛刺,使得平均请求时间变得更加平滑,稳定。

想要做抢占式调度,对于php来说hdmi连接电视无信号,有两个途径

单线程的php的执行流,通过执行指令做文章,可以在php执行流程中注入逻辑,以检查执行时间,再加上swoole的协程能力,可以在不同的协程中切换,以达到抢占cpu的目的。考虑开线程,负责检查当前执行协程执行时间。

经过以上办法的尝试,注入指令的路数基本是无法得到官方的支持,我们只能另谋出路,多开一个线程,只负责检查当前协程。具体的做法是,利用php-7.1.0引入的vm interrupt机制,默认每隔5ms检查一下当前协程是否达到最大执行时间,默认为10ms,如果超过,则让出当前协鹅的诗句程,达到被其他协程抢占的目的。

示例代码

需要
swoole 4.4或更高版本

<?phpco::t(['enable_preemptive_scheduler' => 1]);$start消遣什么意思 = microtime(1);echo "star烦恼的意思t\n";$flag = 1;go(function () u (&$flag) { echo "coro 1 start to loop\n"; $i = 0; for (;;) {  if (!$flag) {   break;  }  $i++; } echo "coro 1 can exit\n";}); $end = microtime(1);$mc = ($end - $start) * 1000;echo "u time $mc\n";go(function () u (&$flag) { echo "coro 2 t flag = fal\n"; $flag = fal;});echo "end\n";

执行结果

startcoro 1 start to loopu time 11.121988296509coro 2 t flag = falendcoro 1 can exit

可以发现,代码逻辑可以从第一个协程的死循环中自动yield出来,执行第二个协程,如果没有这个特性,第二个协程永远不会被执行,导致被饿死。而这样做,第二个协程可以顺利被执行,最后执行结束后,第一个协程也会接着继续往下执行。达到我们的第二个协程主动抢占第一个协程cpu的效果。

这个特性在生产环境非常有用,尤其是对于实时系统或者响应时间比较敏感的场景。

最后

感谢大家对 swoole 的长期支持和关注。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持www.887551.com。

本文发布于:2023-04-07 08:32:20,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/3fc0e1a2473dddaa06e759bc0c33e6c2.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:Swoole4.4协程抢占式调度器详解.doc

本文 PDF 下载地址:Swoole4.4协程抢占式调度器详解.pdf

标签:个协   执行时间   指令   时间
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图