前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >协程篇〡workerman 5.x 协程上下文 Context

协程篇〡workerman 5.x 协程上下文 Context

作者头像
Tinywan
发布2025-02-08 14:01:42
发布2025-02-08 14:01:42
7700
代码可运行
举报
文章被收录于专栏:开源技术小栈
运行总次数:0
代码可运行

协程

协程是一种比线程更轻量级的用户级并发机制,能够在进程中实现多任务调度。它通过手动控制挂起和恢复来实现协程间的切换,避免了进程上下文切换的开销。workerman提供了一个通用的协程接口,底层自动兼容Swoole/Swow/Fiber驱动。

开源技术小栈提示:此特性需要 workerman>=5.1.0

注意

  • 协程仅支持Swoole Swow Fiber驱动
  • 如果使用Fiber驱动时需要安装 composer require revolt/event-loop
  • Swoole或者Swow驱动可以实现PHP阻塞函数自动协程化,从而实现原来的同步代码异步执行
  • Fiber无法像SwooleSwow那样自动协程化,遇到PHP自带的阻塞函数时会阻塞整个进程,并不会发生协程切换
  • 当使用Swoole Swow Fiber驱动时,workerman每次运行onWorkerStart onMessage onConnect onClose等回调时会自动创建一个协程来执行
  • 可以利用$worker->eventLoop=xxx;给不同worker设置不同的协程驱动

案例

coroutine.php文件

代码语言:javascript
代码运行次数:0
复制
<?php
declare(strict_types=1);

use Workerman\Connection\TcpConnection;
use Workerman\Coroutine;
use Workerman\Events\Swoole;
use Workerman\Events\Fiber;
use Workerman\Protocols\Http\Request;
use Workerman\Worker;

require_once __DIR__ . '/vendor/autoload.php';

$worker1 = new Worker('http://0.0.0.0:8201');
$worker1->eventLoop = Swoole::class; // 使用Swoole协程
$worker1->onMessage = function (TcpConnection $connection, Request $request) {
    Coroutine::create(function () {
        echo file_get_contents("http://www.baidu.com");
    });
    $connection->send('Swoole ok');
};

$worker2 = new Worker('http://0.0.0.0:8202');
$worker2->eventLoop = Fiber::class; // 使用自带的Fiber协程
$worker2->onMessage = function (TcpConnection $connection, Request $request) {
    Coroutine::create(function () {
        echo file_get_contents("http://www.baidu.com");
    });
    $connection->send('Fiber ok');
};

Worker::runAll();

启动服务

代码语言:javascript
代码运行次数:0
复制
php coroutine.php start
Workerman[worker.php] start in DEBUG mode
-------------------------------------------- WORKERMAN ---------------------------------------------
Workerman/5.1.0         PHP/8.3.15 (Jit off)          Linux/5.10.102.1-microsoft-standard-WSL2
--------------------------------------------- WORKERS ----------------------------------------------
event-loop  proto       user        worker      listen                 count       state            
swoole      tcp         root        none        http://0.0.0.0:8201    1            [OK]            
fiber       tcp         root        none        http://0.0.0.0:8202    1            [OK]            
----------------------------------------------------------------------------------------------------
Press Ctrl+C to stop. Start success.

访问

  • Swoole 服务 :http://127.0.0.1:8201
  • Fiber 服务 :http://127.0.0.1:8202

协程提供的接口

代码语言:javascript
代码运行次数:0
复制
interface CoroutineInterface
{

    /**
     * 创建协程并立即执行
     */
    public static function create(callable $callable, ...$data): CoroutineInterface;

    /**
     * 开始协程运行
     */
    public function start(mixed ...$args): mixed;

    /**
     * 恢复协程运行
     */
    public function resume(mixed ...$args): mixed;

    /**
     * 获取协程id
     */
    public function id(): int;

    /**
     * 设置协程销毁时的回调
     */
    public static function defer(callable $callable): void;

    /**
     * 暂停当前协程
     */
    public static function suspend(mixed $value = null): mixed;

    /**
     * 获取当前协程
     */
    public static function getCurrent(): CoroutineInterface|Fiber|SwowCoroutine|static;

    /**
     * 判断当前是否是协程环境
     */
    public static function isCoroutine(): bool;

}

关于协程

优势

PHP引入协程后最大的作用就是可以用同步的方式编写异步代码,避免了回调地狱,提高了代码的可读性和可维护性。

协程能大幅度提升IO密集型业务的弹性,可以用较少的进程提供更大的吞吐量。

劣势

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

引入协程后产生了协程创建、调度、销毁、连接池等额外开销。通过大量压测数据来看,在充分利用CPU的情况下,引入协程后极限性能比阻塞式IO下降约10%-20%。

Context 协程上下文

Context用于在协程中存储和传递上下文信息,例如数据库连接、用户信息等。每个协程有自己的上下文,不同协程之间的上下文是隔离的。

开源技术小栈注意:底层自动识别驱动类型,仅支持Swoole/Swow/Fiber驱动

开源技术小栈提示:此特性需要 workerman>=5.1.0

案例

context.php

代码语言:javascript
代码运行次数:0
复制
<?php

declare(strict_types=1);

use Workerman\Connection\TcpConnection;
use Workerman\Coroutine;
use Workerman\Coroutine\Context;
use Workerman\Events\Swoole;
use Workerman\Protocols\Http\Request;
use Workerman\Worker;

require_once __DIR__ . '/vendor/autoload.php';

$worker = new Worker('http://0.0.0.0:8201');

$worker->eventLoop = Swoole::class; // Or Swow::class or Fiber::class

$worker->onWorkerStart = function () {
    Context::set('user_info_onWorkerStart', ['id' => 1, 'name' => 'onWorkerStart']);
};
$worker->onMessage = function (TcpConnection $connection, Request $request) {
    // 协程间context数据是隔离的,所以onMessage协程里获取onWorkerStart协程里的user_info_onWorkerStart是null
    var_dump(Context::get('user_info_onWorkerStart'));

    // 在当前协程设置context数据
    Context::set('user_info', ['id' => 2025, 'name' => 'Tinywan']);
    // 新建协程
    Coroutine::create(function () use ($connection) {
        // 协程间context数据是隔离的,所以新协程里获取的是null
        $userInfo = Context::get('user_info');
        var_dump($userInfo); // 输出null

        Context::set('user_info_new', ['id' => 1, 'name' => 'New Coroutine']);
    });
    // 协程间context数据是隔离的,所以获取新协程里的数据是null
    var_dump(Context::get('user_info_new')); // 输出null

    // 获取当前协程的context数据
    $userInfo = Context::get('user_info'); // 得到['id' => 2025, 'name' => 'Tinywan']
    $connection->send(json_encode($userInfo));
};

Worker::runAll();

启动服务

代码语言:javascript
代码运行次数:0
复制
php context.php start

访问服务

请求地址http://127.0.0.1:8201,响应输出

代码语言:javascript
代码运行次数:0
复制
{
  "id": 2025,
  "name": "Tinywan"
}

接口说明

代码语言:javascript
代码运行次数:0
复制
interface ContextInterface
{
    /**
     * 获取上下文中的值
     */
    public static function get(string $name, mixed $default = null): mixed;

    /**
     * 设置上下文中的值
     */
    public static function set(string $name, mixed $value): void;

    /**
     * 检查上下文中是否存在指定名称的值
     */
    public static function has(string $name): bool;

    /**
     * 重置当前协程上下文
     */
    public static function reset(?ArrayObject $data = null): void;

    /**
     * 销毁上下文
     */
    public static function destroy(): void;

}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-02-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 开源技术小栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 协程
  • 注意
  • 案例
    • 启动服务
    • 访问
  • 协程提供的接口
  • 关于协程
    • 优势
    • 劣势
  • Context 协程上下文
    • 案例
    • 启动服务
    • 访问服务
  • 接口说明
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档