当前位置: 首页 > 后端技术 > PHP

Co--cancel()

时间:2023-03-29 18:30:33 PHP

,Swoolev4.7版本的新特性预览,相信之前很多用户都想要一个取消协程的API,但是好久没有添加了,现在来了v4.7版本新增:具体实现见:#4247、#4249NewAPI&Constant新增两个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()。可能有两种情况:协程不存在。SWOOLE_ERROR_CO_NOT_EXISTS协程处于不可取消状态。SWOOLE_ERROR_CO_CANNOT_CANCEL可以通过Co::isCanceled()判断当前操作是否被手动取消,手动取消正常结束返回true,失败返回false目前基本支持取消大多数协程API,包括:socketAsyncIO(fread,gethostbyname...)sleepwaitSignalwait/waitpidwaitEventCo::suspend/Co::yieldchannelnativecurl(SWOOLE_HOOK_NATIVE_CURL)有两种不间断场景。由CPU中断调度器强制切换的协程文件锁操作过程中,但后续版本也可能允许取消,敬请期待基于协程取消功能的使用场景。协程取消功能可在用户侧实现:timeoutfusebased在协程粒度上。在之前的版本中,被挂起的协程是不能被主动调度的,而Co::cancel()和Co::resume()是不仅可以取消手动的Co::yield()协程,所有允许取消的协程都可以可以取消。更好的API设计不同于传统PHP中类似功能的API。Swoole中大量的API添加了超时参数。当然也有一些比较难加或者不合适加超时参数的,比如文件操作系列函数。现在一切都有了可能,任何IO操作的超时都可以在PHP层实现而不依赖底层API设计实例下面我们通过一些示例代码来理解协程取消的用法:当前协程和不存在的协程无法在协程容器中发起取消操作自动创建协程,并调用Co::cancel()取消,此时无法取消;同时,协程容器中只有一个协程,取消一个不存在的协程程也是不可能的。使用Swoole\Coroutine;使用函数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::yield、AsyncIO和channel中使用sleep来伪造超时后执行取消Co::suspend/Co::yielduseSwoole\Coroutine;useSwoole\Coroutine\System;usefunctionSwoole\Coroutine\run;usefunctionSwoole\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);});AsyncIOuseSwoole\Coroutine;useSwoole\Event;useSwoole\Coroutine\System;usefunctionSwoole\Coroutine\run;run(function(){$cid=Coroutine::getCid();Event::defer(function()use($cid){assert(Coroutine::cancel($cid)===true);});$retval=System::gethostbyname('www.baidu.com');echo"完成\n";断言($retval===false);断言(swoole_last_error()===SWOOLE_ERROR_AIO_CANCELED);});channeluseSwoole\Coroutine;useSwoole\Coroutine\System;usefunctionSwoole\Coroutine\run;usefunctionSwoole\Coroutine\go;run(function(){$chan=newCoroutine\Channel(1);$cid=Coroutine::getCid();go(function()use($cid){System::sleep(0.002);assert(Coroutine::cancel($cid)===true);});assert($chan->push("helloworld[1]",100)===true);assert(Coroutine::isCanceled()===false);assert($chan->errCode===SWOOLE_CHANNEL_OK);assert($chan->push("helloworld[2]",100)===false);assert(Coroutine::isCanceled()===true);assert($chan->errCode===SWOOLE_CHANNEL_CANCELED);echo"Done\n";});当外部使用当Co::cancel()取消协程的挂起状态时,协程调用的API会立即返回失败,程序代码会通过判断协程运行函数/方法的返回值和错误码继续向下执行,或者使用Co::isCanceled()判断是否取消。