PHP的协程革命——从Generator到Fibers的异步演进

简介: PHP作为传统的同步阻塞语言,在很长一段时间内缺乏对高并发I/O场景的原生支持。

PHP作为传统的同步阻塞语言,在很长一段时间内缺乏对高并发I/O场景的原生支持。随着Swoole、ReactPHP等异步框架的兴起,以及PHP 8.1引入的Fibers,PHP的异步编程能力经历了从无到有、从弱到强的演进。这场协程革命正在改变PHP在高性能网络应用中的地位。
参考:https://qeext.cn/category/guide.html

Generator是PHP 5.5引入的协程雏形。Generator允许函数使用yield关键字暂停执行,并在需要时恢复。与传统函数不同,Generator返回的是一个迭代器对象,调用current()、next()等方法可以控制函数的执行流程。虽然Generator并非为异步编程设计,但聪明的开发者发现可以用它实现协程——通过yield暂停函数,等待I/O完成后再通过send()方法恢复。

基于Generator的协程库(如ReactPHP的Promise和Amp的async/await模拟)在PHP社区取得了一定成功。但Generator的根本限制在于:它只能暂停在yield语句处,不能在任何嵌套函数调用中暂停。这意味着如果你调用一个函数,该函数内部无法yield到最外层。这种“不对称”限制使得基于Generator的协程难以构建复杂的异步调用链。

Swoole是PHP异步领域的重大突破。Swoole扩展将事件循环、协程调度器和网络服务器引擎打包为C扩展,提供了PHP原生级别的异步能力。Swoole的协程是对称协程——任何函数都可以在任何深度调用Co::yield()挂起协程,调度器会自动切换到其他可运行的协程。

Swoole的核心设计是hook机制。通过Co::set(['hook_flags' => SWOOLE_HOOK_ALL]),Swoole可以替换PHP内置函数(如sleep、file_get_contents、mysql_connect等)的非阻塞版本。这意味着原有的同步代码几乎不需要修改就能获得协程能力——当调用这些函数时,当前协程自动让出,等待I/O完成后恢复。这种“透明协程化”极大地降低了迁移成本。

Swoole的协程调度器基于栈式协程实现。每个协程拥有独立的栈空间(初始默认为2MB),当协程挂起时,其栈内容被保存到堆内存;恢复时再恢复栈内容。这种实现与Go语言的goroutine类似,但Swoole的协程是单线程的——所有协程运行在同一个OS线程上,无需处理数据竞争,但也不能利用多核CPU。
参考:https://qeext.cn/category/maintenance.html

Swoole的生态包括:HTTP服务器、WebSocket服务器、TCP/UDP服务器、以及各种客户端(MySQL、Redis、PostgreSQL等)。这些组件都是协程感知的,可以实现极高的并发能力。在Swoole上运行的PHP应用,其性能可以媲美Go和Node.js。

PHP 8.1的Fibers是官方对协程的标准化尝试。Fiber是轻量级的用户态线程,提供了比Generator更完整的协程语义。与Generator不同,Fiber可以在任何调用深度暂停和恢复,无需函数的调用者配合yield。

Fiber的API设计简洁:Fiber::__construct(callable $callback)创建Fiber;Fiber::start(mixed ...$args)启动Fiber;Fiber::suspend(mixed $value = null)在Fiber内部挂起,返回给调用者;Fiber::resume(mixed $value = null)恢复挂起的Fiber。Fiber支持在两个方向传递值——挂起时可以向调用者返回值,恢复时可以向Fiber传递值。

Fiber的设计哲学是“提供原语,而非框架”。与Swoole不同,Fiber本身不提供事件循环或非阻塞I/O。它只是提供了暂停和恢复函数执行的能力,真正的异步能力需要与事件循环(如ReactPHP的事件循环)结合使用。这种设计保持了PHP核心的简洁性,将复杂性留给用户态库。

Fiber的典型用法是改写同步阻塞代码为异步。例如,一个使用file_get_contents的同步函数,可以通过Fiber+事件循环改造成非阻塞版本。在等待I/O时,Fiber挂起,事件循环处理其他事件;I/O完成后,Fiber恢复。

性能对比:Swoole协程的上下文切换开销约为几十纳秒,与Go相当;Fiber+用户态事件循环的开销略高,但仍然远低于进程/线程切换。Swoole在极端性能场景下仍占优势,但Fiber作为标准特性,具有更好的可移植性和生态兼容性。
参考:https://qeext.cn/category/limited.html

实际应用场景:协程最适合I/O密集型应用,如API网关、消息推送服务、爬虫系统、以及实时数据处理。对于CPU密集型任务(如图像处理、加解密),协程没有帮助,甚至可能因协程切换增加开销。

陷阱与注意事项:在协程中使用sleep()会阻塞整个事件循环,应使用非阻塞版本的Co::sleep()或usleep的事件循环版本。全局变量和静态变量在协程间是共享的,需要注意并发安全。Swoole的协程不支持多线程,不能利用多核CPU——要利用多核,需要启动多个Swoole进程(worker进程)。

未来展望:PHP社区正在讨论将协程纳入核心语言的可能性。RFC提案包括将Fiber与标准事件循环集成,以及提供原生的异步I/O函数。如果这些提案被采纳,PHP将成为一门“天生异步”的语言,彻底改变其在网络编程领域的定位。

协程的演进是PHP走向现代化的标志之一。从Generator到Swoole再到Fiber,PHP正在补齐异步编程这块短板。对于PHP开发者而言,现在正是学习协程的最佳时机——无论是Swoole还是Fiber,都将成为未来高性能PHP应用的基石。
参考:https://qeext.cn/category/original.html

目录
相关文章
|
存储 缓存 文件存储
如何保证分布式文件系统的数据一致性
分布式文件系统需要向上层应用提供透明的客户端缓存,从而缓解网络延时现象,更好地支持客户端性能水平扩展,同时也降低对文件服务器的访问压力。当考虑客户端缓存的时候,由于在客户端上引入了多个本地数据副本(Replica),就相应地需要提供客户端对数据访问的全局数据一致性。
32704 79
如何保证分布式文件系统的数据一致性
|
前端开发 容器
HTML5+CSS3前端入门教程---从0开始通过一个商城实例手把手教你学习PC端和移动端页面开发第8章FlexBox布局(上)
HTML5+CSS3前端入门教程---从0开始通过一个商城实例手把手教你学习PC端和移动端页面开发第8章FlexBox布局
17758 20
|
设计模式 存储 监控
设计模式(C++版)
看懂UML类图和时序图30分钟学会UML类图设计原则单一职责原则定义:单一职责原则,所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原因。bad case:IPhone类承担了协议管理(Dial、HangUp)、数据传送(Chat)。good case:里式替换原则定义:里氏代换原则(Liskov 
36686 20
设计模式(C++版)
|
存储 编译器 C语言
抽丝剥茧C语言(初阶 下)(下)
抽丝剥茧C语言(初阶 下)
|
机器学习/深度学习 人工智能 自然语言处理
带你简单了解Chatgpt背后的秘密:大语言模型所需要条件(数据算法算力)以及其当前阶段的缺点局限性
带你简单了解Chatgpt背后的秘密:大语言模型所需要条件(数据算法算力)以及其当前阶段的缺点局限性
24767 14
|
机器学习/深度学习 弹性计算 监控
重生之---我测阿里云U1实例(通用算力型)
阿里云产品全线降价的一力作,2023年4月阿里云推出新款通用算力型ECS云服务器Universal实例,该款服务器的真实表现如何?让我先测为敬!
36666 15
重生之---我测阿里云U1实例(通用算力型)
|
SQL 存储 弹性计算
Redis性能高30%,阿里云倚天ECS性能摸底和迁移实践
Redis在倚天ECS环境下与同规格的基于 x86 的 ECS 实例相比,Redis 部署在基于 Yitian 710 的 ECS 上可获得高达 30% 的吞吐量优势。成本方面基于倚天710的G8y实例售价比G7实例低23%,总性价比提高50%;按照相同算法,相对G8a,性价比为1.4倍左右。
|
存储 算法 Java
【分布式技术专题】「分布式技术架构」手把手教你如何开发一个属于自己的限流器RateLimiter功能服务
随着互联网的快速发展,越来越多的应用程序需要处理大量的请求。如果没有限制,这些请求可能会导致应用程序崩溃或变得不可用。因此,限流器是一种非常重要的技术,可以帮助应用程序控制请求的数量和速率,以保持稳定和可靠的运行。
29840 52

热门文章

最新文章

下一篇
开通oss服务