Swoole v4.7 版本新特性预览之 Co::cancel()

简介: 相信之前就有很多用户想要一个取消协程的 API,迟迟没有添加进来,现在在 v4.7 版本中进行了添加:具体实现见:#4247 ,#4249

新增 API & 常量

新增了两个 API,分别为

Co::cancel($cid): bool

用于取消某个协程,但不能对当前协程发起取消操作

Co::isCanceled(): bool

用于判断当前协程是不是被取消的


新增了三个错误码:

常量 含义
SWOOLE_ERROR_CO_CANNOT_CANCEL 协程不能取消
SWOOLE_ERROR_CO_NOT_EXISTS 协程不存在
SWOOLE_ERROR_CO_CANCELED 协程已被取消


说明


该 API 用于从一个协程或者事件回调中取消另外一个协程。

只有处于可取消操作中的协程才能被取消, 当成功取消一个协程时, 上下文环境将会立即切换到对应协程中

尝试取消一个处于不可取消操作中的协程, Co::cancel()成功时返回 true,失败将会返回false,

此时调用swoole_last_error(),可能有两种情况:

  1. 协程不存在 SWOOLE_ERROR_CO_NOT_EXISTS
  2. 协程处于不可取消的状态 SWOOLE_ERROR_CO_CANNOT_CANCEL

可以通过Co::isCanceled()来判断当前操作是否是被手动取消的, 手动取消正常结束, 将返回true, 如失败, 将返回false

目前基本支持了绝大部分的协程 API 的取消,包括:

  1. socket
  2. AsyncIO (fread, gethostbyname ...)
  3. sleep
  4. waitSignal
  5. wait/waitpid
  6. waitEvent
  7. Co::suspend/Co::yield
  8. channel
  9. native curl (SWOOLE_HOOK_NATIVE_CURL)

有两个不可中断的场景

  1. 被 CPU 中断调度器强制切换的协程
  2. 文件锁操作期间

不过,可能在后续版本也会允许进行取消,敬请期待


使用场景


基于协程取消这一功能,可以在用户侧实现:

  • 基于协程粒度的超时熔断

在之前的版本中已挂起的协程是不可主动调度的,而Co::cancel()Co::resume()的区别就是,不止可以取消手动Co::yield()的协程,可以取消一切允许取消的协程。

  • 更好的 API 设计

和传统 PHP 的类似功能的 API 不同的是, Swoole 中大量的 API 增加了 timeout 参数, 当然也有部分难以添加或者说不合适添加 timeout 参数的, 比如文件操作系列函数, 现在一切都有了可能, 可以在 PHP 层实现任意 IO 操作的超时, 而无需依赖于底层的 API 设计


示例


下面来看一些示例代码,了解一下协程取消的用法:


不能对当前协程以及不存在的协程发起取消操作

在协程容器中自动创建了一个协程,就调用Co::cancel()进行取消,这时是不能取消的;同时协程容器中只有一个协程,去取消一个不存在的协程也是不可以的。

use Swoole\Coroutine;
use function Swoole\Coroutine\run;
run(function () {
    assert(Coroutine::cancel(Coroutine::getCid()) === false);
    assert(swoole_last_error() === SWOOLE_ERROR_CO_CANNOT_CANCEL);
    assert(Coroutine::cancel(999) === false);
    assert(swoole_last_error() === SWOOLE_ERROR_CO_NOT_EXISTS);
});

以下三个示例分别演示了在Co::suspend/Co::yieldAsyncIOchannel中使用sleep来伪造timeout后进行取消

Co::suspend/Co::yield

use Swoole\Coroutine;
use Swoole\Coroutine\System;
use function Swoole\Coroutine\run;
use function Swoole\Coroutine\go;
run(function () {
    $cid = Coroutine::getCid();
    go(function () use ($cid) {
        System::sleep(0.002);
        assert(Coroutine::cancel($cid) === true);
    });
    $retval = Coroutine::suspend();
    echo "Done\n";
    assert($retval === false);
    assert(swoole_last_error() === SWOOLE_ERROR_CO_CANCELED);
});

AsyncIO

use Swoole\Coroutine;
use Swoole\Event;
use Swoole\Coroutine\System;
use function Swoole\Coroutine\run;
run(function () {
    $cid = Coroutine::getCid();
    Event::defer(function () use ($cid) {
        assert(Coroutine::cancel($cid) === true);
    });
    $retval = System::gethostbyname('www.baidu.com');
    echo "Done\n";
    assert($retval === false);
    assert(swoole_last_error() === SWOOLE_ERROR_AIO_CANCELED);
});

channel

use Swoole\Coroutine;
use Swoole\Coroutine\System;
use function Swoole\Coroutine\run;
use function Swoole\Coroutine\go;
run(function () {
    $chan = new Coroutine\Channel(1);
    $cid = Coroutine::getCid();
    go(function () use ($cid) {
        System::sleep(0.002);
        assert(Coroutine::cancel($cid) === true);
    });
    assert($chan->push("hello world [1]", 100) === true);
    assert(Coroutine::isCanceled() === false);
    assert($chan->errCode === SWOOLE_CHANNEL_OK);
    assert($chan->push("hello world [2]", 100) === false);
    assert(Coroutine::isCanceled() === true);
    assert($chan->errCode === SWOOLE_CHANNEL_CANCELED);
    echo "Done\n";
});

当外部使用 Co::cancel() 取消一个协程的挂起状态时,该协程所调用的 API 会立即返回失败,程序代码会继续向下执行。

通过判断协程操作函数/方法返回值和错误码,或者使用 Co::isCanceled() 判断是不是被取消。


目录
相关文章
|
传感器 机器学习/深度学习 自动驾驶
自动驾驶:BEV开山之作LSS(lift,splat,shoot)原理代码串讲
自动驾驶:BEV开山之作LSS(lift,splat,shoot)原理代码串讲
5173 1
自动驾驶:BEV开山之作LSS(lift,splat,shoot)原理代码串讲
|
SQL 数据库
SQL面试50题------(初始化工作、建立表格)
这篇文章提供了SQL面试中可能会遇到的50道题目的建表和初始化数据的SQL脚本,包括学生、教师、课程和成绩表的创建及数据插入示例。
SQL面试50题------(初始化工作、建立表格)
|
7月前
|
算法 物联网 Swift
Qwen3 X ModelScope工具链: 飞速训练 + 全面评测
Qwen于近日发布了Qwen3系列模型,包含了各个不同规格的Dense模型和MoE模型。开源版本中,Dense模型基本沿用了之前的模型结构,差别之处在于对于Q和K两个tensor增加了RMSNorm;MoE模型去掉了公共Expert,其他结构基本与前一致。在模型大小上,涵盖了从0.6B到32B(Dense)和235B(MoE)不同的尺寸。
1089 15
|
运维 数据可视化 网络协议
Docker可视化工具Portainer的安装和使用
Docker可视化工具Portainer的安装和使用
17305 1
Docker可视化工具Portainer的安装和使用
|
8月前
|
自然语言处理 前端开发 安全
指南:Claude 3.7 怎么样?国内如何使用Claude 3.7 Sonnet?
本文主要介绍了Claude 3.7 Sonnet模型的发布教你如何订阅使用Claude 3.7 Sonnect及其新功能,特别是Claude Code工具的推出。
4258 7
|
11月前
|
安全 数据管理 关系型数据库
解锁数据管理的无限可能——探索 Teable 多维表格
Teable 是一个基于 Postgres 构建的企业级多维表格解决方案,提供卓越性能、灵活多维表格、丰富视图、精细权限管理、实时协作及自动化工作流等核心特性,支持私有部署,助力企业高效管理海量数据,加速数字化转型。
930 3
|
Kubernetes Go Docker
Kubernetes + CRI + Kata + Firecracker
在最近的AWS re:invent 2018上,AWS又发布了一系列新的产品,在这些产品中,最受关注的无疑就是面向serverless的Firecracker。Firecracker是针对目前现有的虚拟化技术在serverless应用场景中的各种不足,而专门为serverless量身打造的一项新的虚拟化技术。
10137 0
Kubernetes + CRI + Kata + Firecracker
|
存储 Kubernetes 对象存储
Kubernetes版本对接对象存储几种方案
Kubernetes版本对接对象存储几种方案
|
Kubernetes 调度 Perl
k8s中的PVC为何需要延迟绑定?(WaitForFirstConsumer)
有一个pod, 使用的pvc叫pvc-1, 我们希望它只运行在node-2上,在当前的集群中存在两台主机符合pod的pvc的要求, 假如node-1上是pv-1, node-2上是pv-2,这两个完全一样.
747 0