前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Swoole v4.7 版本新特性预览之 Co::cancel()

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

作者头像
沈唁
发布2021-06-25 15:49:05
5350
发布2021-06-25 15:49:05
举报
文章被收录于专栏:沈唁志沈唁志

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

具体实现见:#4247 ,#4249

新增 API & 常量

新增了两个 API,分别为

代码语言:javascript
复制
Co::cancel($cid): bool

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

代码语言:javascript
复制
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. 文件锁操作期间

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

使用场景

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

  1. 基于协程粒度的超时熔断

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

  1. 更好的 API 设计

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

示例

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

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

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

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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() 判断是不是被取消。

代码语言:javascript
复制
好文和朋友一起看~
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-06-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 沈唁志 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 新增 API & 常量
  • 说明
  • 使用场景
  • 示例
    • 不能对当前协程以及不存在的协程发起取消操作
      • Co::suspend/Co::yield
        • AsyncIO
          • channel
          相关产品与服务
          容器服务
          腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档