🧌 实战系列 | 高性能PHP框架webman协程插件入门实战

Tinywan

💐💐 感谢兔子大佬chaz6chez的协程插件 https://www.workerman.net/plugin/167

🐞 简介

🚀🚀 webman-coroutine 是一个 webman 开发框架生态下的协程基建支撑插件

Github:https://github.com/workbunny/webman-coroutine

主要实现以下功能

  1. 支持workerman 4.x的 swow 协程驱动能力,兼容workerman 5.x版本自带的swow协程驱动;
  2. 支持workerman 4.x的 swoole 协程驱动能力,兼容workerman 5.x版本自带的swoole协程驱动;
  3. 实现coroutine web server 用于实现具备协程能力的 web 框架基建
  4. 支持自定义协程实现,如基于revolt

🕷️ 说明

  1. workerman 4.x/5.x驱动下的 webman 框架无法完整使用swoole的协程能力,所以使用CoroutineWebServer来替代webman自带的webServer
  2. workerman 4.x下还未有官方支持的swow协程驱动,本插件提供SwowEvent事件驱动支撑workerman 4.x下的协程能力
  3. 由于配置event-loop等操作相较于普通开发会存在一定的心智负担,所以本插件提供了event_loop()函数,用于根据当前环境自动选择合适的事件驱动

🪰 安装

通过composer安装

composer require workbunny/webman-coroutine

注: 目前在开发阶段,体验请使用dev-main分支

# composer require workbunny/webman-coroutine dev-main
./composer.json has been updated
Running composer update workbunny/webman-coroutine
Loading composer repositories with package information
Updating dependencies
Lock file operations: 6 installs, 0 updates, 0 removals
  - Locking composer/semver (3.4.2)
  - Locking psr/http-client (1.0.3)
  - Locking psr/http-factory (1.0.2)
  - Locking psr/http-message (2.0)
  - Locking swow/swow (v1.5.3)
  - Locking workbunny/webman-coroutine (dev-main 3965bb5)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 6 installs, 0 updates, 0 removals
  - Installing composer/semver (3.4.2): Extracting archive
  - Installing psr/http-message (2.0): Extracting archive
  - Installing psr/http-client (1.0.3): Extracting archive
  - Installing psr/http-factory (1.0.2): Extracting archive
  - Installing swow/swow (v1.5.3): Extracting archive
  - Installing workbunny/webman-coroutine (dev-main 3965bb5): Extracting archive
> support\Plugin::install
> support\Plugin::install
> support\Plugin::install
> support\Plugin::install
> support\Plugin::install
> support\Plugin::install
Create config/plugin/workbunny/webman-coroutine
3 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files
12 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
No security vulnerability advisories found.

配置说明

  • enable : (true/false) 是否启用协程webServer
  • port : (int) 协程webServer默认端口
  • channel_size : (int) 协程webServer默认每个streamchannel容量

🐜 使用

1. swow 环境

  1. 使用./vendor/bin/swow-builder安装swow拓展,注意请关闭swoole环境
  2. 修改config/server.php'event_loop' => \Workbunny\WebmanCoroutine\event_loop()
    event_loop()函数会根据当前环境自行判断当前的 workerman 版本,自动选择合适的事件驱动
    • 当开启swow拓展时,workerman 4.x下使用SwowEvent事件驱动
    • 当开启swow拓展时,workerman 5.x下使用workerman自带的Swow事件驱动
    • 当未开启swow时,使用workerman自带的Event事件驱动
  3. 使用php -d extension=swow webman start启动
  4. webman 自带的 webServer 协程化,可以关闭启动的CoroutineWebServer

注:CoroutineWebServer可以在config/plugin/workbunny/webman-coroutine/app.php中通过enable=false关闭启动

通过以下命令启动

php -d extension=swow webman start

启动输出

# php -d extension=swow webman start
Workerman[webman] start in DEBUG mode
----------------- WORKERMAN ------------------------------------
Workerman version:4.1.15          PHP version:8.3.9   Event-Loop:Workbunny\WebmanCoroutine\Events\SwowEvent
----------------- WORKERS ---------------------------------------
proto   user            worker                         listen                      processes    status
tcp     root            webman                          http://0.0.0.0:8217         8             [OK]
tcp     root            monitor                         none                        1             [OK]
tcp     root            push_chart                      none                        1             [OK]
tcp     root            plugin.webman.push.server       websocket://0.0.0.0:8788    1             [OK]
tcp     root            plugin.workbunny.webman-coroutine.coroutine-web-server    http://[::]:8717            2             [OK]
------------------------------------------------------------------------
Press Ctrl+C to stop. Start success.

2. swoole 环境

  1. 使用pecl install swoole安装稳定版 swoole 拓展
  2. 建议不要将swoole加入php.ini配置文件
  3. 修改config/server.php'event_loop' => \Workbunny\WebmanCoroutine\event_loop()
    event_loop()函数会根据当前环境自行判断当前的 workerman 版本,自动选择合适的事件驱动
    • 当开启 swoole 拓展时,workerman 4.x 下使用 SwooleEvent 事件驱动
    • 当开启 swoole 拓展时,workerman 5.x 下使用 workerman 自带的 Swoole 事件驱动
    • 当未开启 swoole 时,使用 workerman 自带的 Event 事件驱动
  4. 使用php -d extension=swoole webman start启动
  5. 通过config/plugin/workbunny/webman-coroutine/process.php启动的 CoroutineWebServer 可以用于协程环境开发,原服务还是 BIO 模式

3. ripple 环境

  1. 使用composer require cclilshy/p-ripple-drive安装 ripple 驱动插件
  2. 修改config/server.php配置
    • 'event_loop' => \Workbunny\WebmanCoroutine\event_loop()自动判断,请勿开启 swow、swoole,
    • 'event_loop' => \Workbunny\WebmanCoroutine\Factory::RIPPLE_FIBER手动指定
  3. 使用php webman start启动

注:该环境协程依赖php-fiber,并没有自动hook系统的阻塞函数,但支持所有支持php-fiber的插件

4. 自定义环境

  1. 实现Workbunny\WebmanCoroutine\Handlers\HandlerInterface接口,实现自定义协程处理逻辑
  2. 通过Workbunny\WebmanCoroutine\Factory::register(HandlerInterface $handler)注册你的协程处理器
  3. 修改config/server.php'event_loop' => {你的事件循环类}
  4. 启动CoroutineWebServer 接受处理协程请求

注:\Workbunny\WebmanCoroutine\event_loop()自动判断加载顺序按\Workbunny\WebmanCoroutine\Factory::$_handlers的顺序执行available()择先

注:因为eventLoopClassHandlerClass是一一对应的,所以建议不管是否存在相同的事件循环或者相同的处理器都需要继承后重命名

自定义协程化

webman-coroutine提供了用于让自己的自定义服务/进程协程化的基础工具

注:考虑到 webman 框架默认不会启用注解代理,所以这里没有使用注解代理来处理协程化代理

1. 自定义进程

假设我们已经存在一个自定义服务类,如MyProcess.php

namespace process;

class MyProcess {
    public function onWorkerStart() {
        // 具体业务逻辑
    }
    // ...
}

webman/workerman环境中,onWorkerStart()是一个 worker 进程所必不可少的方法,
假设我们想要将它协程化,在不改动MyProcess的情况下,只需要新建一个MyCoroutineProcess.php

namespace process;

use Workbunny\WebmanCoroutine\CoroutineWorkerInterface;
use Workbunny\WebmanCoroutine\CoroutineWorkerMethods;

class MyCoroutineProcess extends MyProcess implements CoroutineWorkerInterface {

    // 引入协程代理方法
    use CoroutineWorkerMethods;
}

此时的MyCoroutineProcess将拥有协程化的onWorkerStart(),将新建的MyCoroutineProcess添加到 webman 的自定义进程配置config/process.php中启动即可

2. 自定义服务

代码样例:CoroutineWebServer.php

假设我们已经存在一个自定义服务类,如MyServer.php

namespace process;

class MyServer {

    public function onMessage($connection, $data) {
        // 具体业务逻辑
    }

    // ...
}

webman/workerman环境中,onMessage()是一个具备监听能力的进程所必不可少的方法,假设我们想要将它协程化,在不改动MyServer的情况下,只需要新建一个MyCoroutineServer.php

namespace process;

use Workbunny\WebmanCoroutine\CoroutineServerInterface;
use Workbunny\WebmanCoroutine\CoroutineServerMethods;

class MyCoroutineServer extends MyServer implements CoroutineServerInterface {

    // 引入协程代理方法
    use CoroutineServerMethods;
}

此时的MyCoroutineServer将拥有协程化的onMessage(),将新建的MyCoroutineServer添加到 webman 的自定义进程配置config/process.php中启动即可

协程入门

1. 协程创建

Swow 的协程是面向对象的,所以我们可以这样创建一个待运行的协程

use Swow\Coroutine;

$coroutine = new Coroutine(static function (): void {
    echo "Hello 开源技术小栈\n";
});

这样创建出来的协程并不会被运行,而是只进行了内存的申请。

2. 协程的观测

通过 var_dump 打印协程对象,我们又可以看到这样的输出:

var_dump($coroutine);

打印输出

class Swow\Coroutine#240 (4) {
  public $id =>
  int(12)
  public $state =>
  string(7) "waiting"
  public $switches =>
  int(0)
  public $elapsed =>
  string(3) "0ms"
}

从输出我们可以得到一些协程状态的信息,如:协程的 id12,状态是等待中,切换次数是0,运行了0毫秒(即没有运行)。

通过 resume() 方法,我们可以唤醒这个协程:

$coroutine->resume();

协程中的PHP代码被执行,于是我们就看到了下述信息:

Hello 开源技术小栈

这时候我们再通过 var_dump($coroutine); 去打印协程的状态,我们得到以下内容:

class Swow\Coroutine#240 (4) {
  public $id =>
  int(12)
  public $state =>
  string(4) "dead"
  public $switches =>
  int(1)
  public $elapsed =>
  string(3) "0ms"
}

可以看到协程已经运行完了所有的代码并进入dead状态,共经历一次协程切换。

♨️ 相关文章

©️ 版权声明
作者:Tinywan
原文:https://mp.weixin.qq.com/s/SoyKa9zplMybCJ_n7YlW0Q
本文版权归作者和workerman官方共有。欢迎转载,但必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
欢迎关注 [开源技术小栈] 微信公众号,一起进步!扫描下方二维码即可

989 10 4
10个评论

Tinywan

  • 暂无评论
深林孤鹰

非常棒的文章!能介绍一下如何协程CURD就好了~
另外微信公众号的文章,用手机上所有浏览器都打不开(卡退),不知是不是图片太多的缘故

释永战

学习了····

  • 暂无评论
初心by

爱了爱了

  • 暂无评论
深蓝

从FPM转到CLI,觉得性能已经很强了,现在又加上协程,这是要起飞呀。

  • 暂无评论
saithink

Great group of guys!

  • 暂无评论
weijer

强!!!!!!

workerman 还差一个原生 http2 server 支持了就完美了

  • 暂无评论
深林孤鹰

windows下测试了一番,会报错(访问页面时):

Error: Class "Swow\Coroutine" not found in D:\Documents\Desktop\testWebman\webman-coroutine\app\controller\IndexController.php:31
Stack trace:
#0 D:\Documents\Desktop\testWebman\webman-coroutine\vendor\workerman\webman-framework\src\App.php(322): app\controller\IndexController->test1(Object(support\Request))
#1 D:\Documents\Desktop\testWebman\webman-coroutine\vendor\workerman\webman-framework\src\App.php(169): Webman\App::Webman\{closure}(Object(support\Request))
#2 D:\Documents\Desktop\testWebman\webman-coroutine\vendor\workerman\workerman\Connection\TcpConnection.php(646): Webman\App->onMessage(Object(Workerman\Connection\TcpConnection), Object(support\Request))
#3 D:\Documents\Desktop\testWebman\webman-coroutine\vendor\workerman\workerman\Events\Select.php(311): Workerman\Connection\TcpConnection->baseRead(Resource id #165)
#4 D:\Documents\Desktop\testWebman\webman-coroutine\vendor\workerman\workerman\Worker.php(1488): Workerman\Events\Select->loop()
#5 D:\Documents\Desktop\testWebman\webman-coroutine\vendor\workerman\workerman\Worker.php(1405): Workerman\Worker::forkWorkersForWindows()
#6 D:\Documents\Desktop\testWebman\webman-coroutine\vendor\workerman\workerman\Worker.php(560): Workerman\Worker::forkWorkers()
#7 D:\Documents\Desktop\testWebman\webman-coroutine\vendor\workerman\webman-framework\src\support\App.php(131): Workerman\Worker::runAll()
#8 D:\Documents\Desktop\testWebman\webman-coroutine\start.php(4): support\App::run()
#9 {main}

在《webman如何使用swow事件驱动和协程?》文章中测试,仍然是这个报错(启动webman时);
我已经严格按照教程的步骤做的,php为8.3,swow的官方编译好的dll也放在ext目录下,64位 和 nts 都一致,启动命令:php -d extension=swow windows.php,config.php配置'event_loop' => \Workbunny\WebmanCoroutine\event_loop()(此文章)'event_loop' => \Workerman\Events\Swow::class(后面文章)。

  • Tinywan 2024-09-28

    先用unix用哦,windows.还没怎么兼容

  • Tinywan 2024-09-28

    重启webman试试,你这是没加载到类

  • 深林孤鹰 2024-09-28

    重启也不行,很奇怪,而且我用webman+swow也是这个报错。。

tesla

好文章,最新正在尝试携程相关内容

lsmir2

cclilshy/p-ripple-drive 这包弃用了

  • 暂无评论

Tinywan

13130
积分
0
获赞数
0
粉丝数
2020-01-14 加入
×
🔝