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() 判断是不是被取消。


沈唁
+关注
目录
打赏
0
0
0
0
1
分享
相关文章
指南:Claude 3.7 怎么样?国内如何使用Claude 3.7 Sonnet?
本文主要介绍了Claude 3.7 Sonnet模型的发布教你如何订阅使用Claude 3.7 Sonnect及其新功能,特别是Claude Code工具的推出。
3638 7
|
4月前
|
Linux 进程前台后台切换与作业控制
进程前台/后台切换及作业控制简介: 在 Shell 中,启动的程序默认为前台进程,会占用终端直到执行完毕。例如,执行 `./shella.sh` 时,终端会被占用。为避免不便,可将命令放到后台运行,如 `./shella.sh &`,此时终端命令行立即返回,可继续输入其他命令。 常用作业控制命令: - `fg %1`:将后台作业切换到前台。 - `Ctrl + Z`:暂停前台作业并放到后台。 - `bg %1`:让暂停的后台作业继续执行。 - `kill %1`:终止后台作业。 优先级调整:
221 5
MV-MATH:中科院开源多模态数学推理基准,多视觉场景评估新标杆
MV-MATH 是中科院自动化所推出的多模态数学推理基准数据集,旨在评估多模态大语言模型在多视觉场景中的数学推理能力。该数据集包含2009个高质量的数学问题,涵盖11个数学领域和3个难度级别,适用于智能辅导系统和多模态学习研究。
103 0
实时计算 Flink版操作报错合集之遇到akka.remote.OversizedPayloadException错误,如何处理
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
北极星指标是什么
北极星指标是什么
683 0
Kubernetes + CRI + Kata + Firecracker
在最近的AWS re:invent 2018上,AWS又发布了一系列新的产品,在这些产品中,最受关注的无疑就是面向serverless的Firecracker。Firecracker是针对目前现有的虚拟化技术在serverless应用场景中的各种不足,而专门为serverless量身打造的一项新的虚拟化技术。
9653 0
Kubernetes + CRI + Kata + Firecracker
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问