桓楠百科网

编程知识、经典语录与百科知识分享平台

php 明星开源项目workerman(github star 11.2k)发布v5版本-协程化

拍h片的朋友们,来吧,今天在推广下php优秀开源生态项目workerman,workman官方在新年的第一天发布了5.0版本,就让我们来看看更新了啥!

关于workerman

workerman是一款开源高性能PHP应用容器,它大大突破了传统PHP应用范围,被广泛的用于互联网、即时通讯、APP开发、硬件通讯、智能家居、物联网等领域的开发。这个项目在GitHub上目前star:11.2k, 妥妥的明星项目。


v5版本

作者说:“v5 的发布标志着性能与稳定性的进一步提升,协程的引入也为开发者们带来了更多可能性。未来,我们将继续携手,共同推动 Workerman 的发展,为更多开发者提供强大的工具与支持。”

主要特性

协程化

workerman取大家之所长,集成了fiber、swoole、swow。

  • 支持Fiber协程
  • 支持Swoole协程
  • 支持Swow协程

注意
同一个Worker中Fiber协程、Swoole协程、Swow协程无法共存,只能使用其中一种。
不同Worker可以设置不同的协程驱动类型

Fiber协程

composer require revolt/event-loop ^1.0.0
eventLoop = Revolt::class;
$worker->onMessage = function (TcpConnection $connection, Request $request) {
    $connection->send('hello workerman');
};

Worker::runAll();

Swoole协程

安装Swoole

测试代码

eventLoop = Swoole::class;
$worker->onMessage = function (TcpConnection $connection, Request $request) {
    $connection->send('hello workerman');
};

Worker::runAll();

Swow协程

安装Swow

测试代码

eventLoop = Swow::class;
$worker->onMessage = function (TcpConnection $connection, Request $request) {
    $connection->send('hello workerman');
};

Worker::runAll();

不兼容的变更

websocket协议onWebSocketConnect事件

$worker = new Worker('websocket://0.0.0.0:2345');
$worker->onWebSocketConnect = function (TcpConnection $connection, Request $request) {
    //  不再支持 $_GET $_SERVER 获取参数,统一使用$request获取参数
    $token = $request->get('token');
};

新增接口

  • Timer::public static function repeat($time, $callback, $args) 一次性定时器
    相当于 Timer::add($time, $callback, $args, false)
  • Timer::repeat($time, $callback, $args) 连续性定时器
    相当于 Timer::add($time, $callback, $args)

协程优点

PHP引入协程后最大的作用就是可以用同步的方式编写异步代码,避免了回调地狱,提高了代码的可读性和可维护性。
引入协程后可以让应用有更好的弹性,尤其在慢IO的情况下,能大幅提升应用性能。

协程缺点

但是引入协程后开发者需要时刻注意全局变量污染、资源竞争、第三方库改造等问题,开发维护成本增大,心智负担明显增加。

引入协程后产生了协程创建、调度、销毁、连接池等额外开销。
不管通过swoole自己的压测还是workerman的压测,在充分利用资源的情况下,引入协程后性能比阻塞式IO,MySQL单查询极限性能下降约5%-15%左右,PgSQL单查询性能下降更多。

尽管使用协程极限性能会下降,但是协程在慢IO的业务下会大幅度提高吞吐率。

来自作者walkor的交流



知识总结-协程

协程(Coroutine)是一种轻量级的线程,它允许在单个线程中执行多个任务,并能在任务之间切换而不需要线程切换的开销。协程通过合作式调度来管理任务的执行顺序,避免了传统多线程中的上下文切换(不依赖操作系统调度)。它通常在异步编程中使用,以便在等待 I/O 操作时不会阻塞主线程,从而提高效率。

比喻:协程像一个“多任务的厨师”

想象你是一名厨师,正在准备一顿大餐。你的工作中有多个任务,比如切菜、煮汤、翻煎饼、准备沙拉等。你不能同时做所有事情,但你可以在每项任务的“空闲时间”切换到下一个任务,避免浪费时间等待。

  • 传统的单任务厨师:只做一件事,等一件事做完才能开始下一件事。
  • 多任务的厨师(协程):做一会儿煎饼,等它煎好时去切菜,煎饼好了再回来翻,类似这种在不同任务间“切换”。这个切换不是通过“暂停和重启厨房”,而是在当前任务暂时不需要操作时灵活切换到下一个任务。

这就类似协程:在一个线程中,我们可以在不同的任务之间进行切换,不需要创建多个线程或进程。

协程的执行过程

  • 开始切菜:厨师开始切菜(任务A)。
  • 煮汤开始:厨师开始做第二个任务——煮汤(任务B)。
  • 等待水烧开:煮汤任务进入等待状态。
  • 继续切菜:厨师返回切菜任务(切菜任务在等待时被挂起,执行其他任务)。
  • 做沙拉开始:厨师开始做沙拉(任务C)。
  • 准备沙拉材料:做沙拉任务进入准备阶段。
  • 继续切菜:厨师再次返回切菜任务,继续执行。
  • 水烧开,继续煮汤:水烧开后,煮汤任务继续执行。
  • 完成切菜,开始翻煎饼:切菜完成后,厨师继续翻煎饼(新的任务)。
  • 完成所有任务,结束:所有任务完成,厨师的工作结束

协程的执行时序图:

协程与进程、线程的对比

特性

进程

线程

协程

内存独立性

每个进程有独立的内存空间,彼此隔离

同一进程中的线程共享内存空间

协程通常在同一线程中运行,共享内存

创建与销毁开销

创建和销毁进程的开销较大

创建和销毁线程的开销较大

协程的创建和销毁开销很小

调度方式

操作系统调度,不同进程间的切换有较高开销

操作系统调度,同一进程的线程切换较轻

用户控制调度,协程切换几乎无开销

并发性

每个进程独立运行,可以并行执行

线程在进程中并行执行

单线程并发,任务切换通过协程管理

通信

进程间通信需要专门的机制(如管道、共享内存等)

线程间通信较简单,通过共享内存即可

协程通过函数调用、yield 或 suspend 实现任务间协作

上下文切换

进程切换较重,需要操作系统管理,包含完整的上下文保存和恢复

线程切换有一定的开销,操作系统管理

协程切换非常轻量级,由应用程序控制,几乎没有上下文切换开销

适用场景

适用于独立任务的并行执行,高资源消耗的任务

适用于需要高并发的场景,尤其是计算密集型任务

适用于 I/O 密集型的并发任务,减少阻塞,提高资源利用率


PHP 的 Fibers 协程

PHP 8.1 引入了 Fiber,它为 PHP 提供了协程支持。Fibers 是一种低级的协程机制,允许你在 PHP 中手动控制执行的暂停和恢复。Fibers 本质上是 PHP 中的一种协作式多任务机制,可以在单个请求中调度多个任务,使得异步操作不再依赖于事件循环。

PHP Fiber 的好处:

  1. 减少阻塞
  2. 传统的同步代码往往会在等待 I/O 操作时阻塞程序,导致性能瓶颈。而通过协程,任务可以在等待 I/O 操作时挂起,允许其他任务执行,从而提高并发性和资源利用率。
  3. 更简单的异步编程模型
  4. 使用 Fiber,开发者可以像写同步代码一样编写异步代码,避免了回调地狱(callback hell)的问题。这使得代码结构更清晰,易于理解和维护。
  5. 无需额外的线程开销
  6. 传统的多线程并发模型需要操作系统的线程调度,带来了较高的开销。而协程通过单线程的协作式调度,大大减少了上下文切换的开销。
  7. 易于控制的执行流程
  8. 使用 Fiber,开发者可以精确地控制代码执行的暂停和恢复时机,这对于某些需要精细调度的应用非常有用。例如,在某些 IO 密集型应用中,能在合适的时机暂停任务,等待 I/O 操作完成,然后再恢复执行。
  9. 无需全局事件循环
  10. PHP 的协程机制不需要像 Node.js 那样使用事件循环。通过 Fiber,可以在同步代码中嵌入异步逻辑,而不必依赖复杂的事件驱动架构。
  11. 提高并发性
  12. Fiber 允许在多个任务之间快速切换,这使得在 PHP 中实现并发执行变得更加高效。例如,在高并发情况下,PHP 可以通过 Fiber 挂起当前任务,让其他任务继续执行,从而提高系统的整体吞吐量。
$fiber = new Fiber(function (): void {
    echo "Start\n";
    Fiber::suspend(); // 挂起当前 Fiber
    echo "Resumed\n";
});

echo "Before Fiber\n";
$fiber->start(); // 启动 Fiber
echo "After Fiber Suspend\n";
$fiber->resume(); // 恢复 Fiber
echo "End\n";

总结

最后祝愿:workerman、swoole、swow能走更远。

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言