6、Swift协程详解:属性隔离和Actor

Task 的取消就是个状态

Task 的取消其实非常简单,就是将 Task 标记为取消状态。那 Task 的执行体要怎么做才能让任务真正取消呢?我们先看个简单的例子:

我们创建了一个 Task,正常情况下它应该很快被执行到,因此第一行日志可以打印出来,随即进入 10s 的睡眠状态。但我们在 Task 外部等了 500ms 之后把它取消了,如果不出什么意外的话,在 Task 睡眠时它就被取消了。

既然任务被取消了,凭我们主观的判断,第二句日志应该是打印不出来的,但实际的情况却是:

这说明 Task 的取消只是一个状态标记,它不会强制 Task 的执行体中断,换句话说 Task 的取消并不像杀进程那样粗暴。

实际上,我们可以在任务的执行体当中读取到 Task 的取消状态,我们把程序稍作修改如下:

运行结果如下:

可以看到,Task 确实被取消了,我们也可以读取到这个状态,如果我们需要让我们的 Task 执行体响应它的取消状态,那就需要做出这个状态的判断,并且做出响应,例如:

当然,这个例子还不够理想,毕竟睡眠的 10s 是不能响应取消的。那如果让 sleep 函数内部也能响应取消,问题是不是就解决了?

通过抛 CancellationError 来响应取消

Task 的执行过程中,难免会存在多层异步函数的嵌套的情况,如果最深处的某一个函数响应了取消状态,怎样才能让外部的异步函数也能很好的配合好这个响应?这其实就是在回答上一节留下的 sleep 该如何响应取消的问题。如果想要优雅地给出这个答案,只能通过抛异常的方式了,因为任何条件分支的判断都无法实现有效的传播,而异常天然就具备这样的特性。

所以常见的异常响应方式非常简单,如果你在编写一个需要响应取消状态的异步函数,当你检查到 Task 被取消时,只需要抛一个 CancellationError 即可,大家都遵守这个规则,那么这个 Task 就能被优雅地结束。

实际上 Task 一共有两个 sleep 函数,我们仔细对比一下它们的定义:

二者的区别有两处:

  • 参数的 label
  • 是否会抛出异常

第二个函数明确通过参数的 label 告诉我们参数是纳秒,同时它还会抛出异常。什么异常?自然是在 Task 被取消时抛出 CancellationError。这么看来我们只需要稍微调整一下代码就能完美解决问题:

运行结果如下:

符合预期。

实际上,如果大家仔细查阅 Swift 的文档,你就会发现第一个 sleep 函数已经被废弃了,它的问题想必大家也已经非常明白了吧。

checkCancellation:更方便地检查取消状态

前面的例子我们算是躺赢了,但如果实际的代码是下面这样呢?

不难,我们只需要加个判断嘛,这样在每次循环的开始,如果 Task 已经被取消,我们就能够及时地停止这个任务的执行:

其实,这里有个更方便的写法:

这个函数也没啥神秘的,因为它的实现非常直接:

注册取消回调

前面提到的响应取消的情况实际上是两种类型:

  • 调用其他支持响应取消的异步函数,在取消时它会抛出 CancellationError
  • 自己的代码当中主动检查取消状态,并抛出 CancellationError(或者直接退出执行逻辑)

但如果异步的逻辑封装在第三方代码当中,我们只能想办法在 Task 取消时调用第三方的取消逻辑来完成响应,这时候情况就复杂一些了。我们就以 GCD 的异步 API 为例,首先我们对 DispatchWorkItem 做个包装:

这个包装的目的在于支持 installContinuation,通过获取 Task 的 continuation 来实现异步结果的返回。

这里还有一个细节,block 的类型与 DispatchWorkItem 的 block 多了个参数:

这主要是为了方面我们在 block 当中可以读取到 GCD 的任务是否被取消了。

接下来我们试着用 Task 来封装 GCD 的异步任务,并且实现对取消的响应:

asyncRequest 其实就是我们创建的对 ContinuationWorkItem 实例,它对 DispatchWorkItem 做了包装,在后面的代码当中传给了 DispatchQueue 去异步执行。为了能够及时感知到 Task 的取消状态变化,我们用到了 withTaskCancellationHandler 这个函数,它的定义如下:

显然,这个函数也是个异步函数,它有两个参数,分别是:

  • operation,即我们要在当前 Task 当中执行的代码逻辑
  • onCancel,在 operation 执行时,如果 Task 被取消,该回调立即执行

有了这个函数,我们就可以在调用第三方异步操作时,及时感知到 Task 的取消状态,并通知第三方取消异步操作。

TaskGroup 的取消

TaskGroup 也可以被取消,很容易理解,所有从属于 TaskGroup 的 Task 在前者被取消以后也会被取消。下面我们给出一个非常简单的例子来说明这个问题:

我们在 TaskGroup 当中启动了 10 个 Task, 这些 Task 每隔约 1 ~ 1.5 秒就会令 count 加 1,最终把 Task 的序号和 count 的值返回。TaskGroup 则在启动了所有的 Task 之后 5.5 秒的时候取消,因此前面的 Task 大多只能将 count 增加到 5 左右。运行结果如下:

我们省略了部分相似的输出,大家只需要关注包含 result 的行,其中 Task 9 返回的 count 为 4,Task 1 返回的 count 为 5。这说明 TaskGroup 在取消时其中的 Task 确实都被取消了。

本文我们重点讨论了 Task 的取消的设计,包括取消状态的概念,如何在不同情况下响应取消状态;最后也通过一个简单地例子了解了一下 TaskGroup 的取消。

大家只需要牢记一点,Task 的取消只是一个状态,需要内部执行逻辑的响应。

Original: https://www.cnblogs.com/strengthen/p/16243560.html
Author: 山青咏芝
Title: 6、Swift协程详解:属性隔离和Actor

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/553569/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Vue 中关于页面全屏的样式定义

    vue开发中很需要页面全屏,尤其是实在登录页面的时候. 但是经常设置 height: 100%;不起作用. 原因分析: 给div设置高度100%时,div的高度会等同于其父元素的高…

    技术杂谈 2023年7月11日
    079
  • 文件的压缩与打包

    文件的压缩与打包 常用文件拓展名 *.tar.gz tar程序打包的文件,并且经过gzip的压缩 *.tar.bz2 tar程序打包的文件,并且经过bzip2的压缩 tar 命令,…

    技术杂谈 2023年7月11日
    082
  • Laravel项目中使用GroupBy时报错

    今天用Laravel做一个新的项目,GroupBy一个字段内容为中文时候,一直报错。 $list = ApCategories::where(‘site_code’, ‘MY’) …

    技术杂谈 2023年7月11日
    085
  • Nginx平滑升级版本

    Nginx平滑升级版本 一, 查看现目前版本,准备预升级版本的安装包 #查看nginx版本 /usr/local/nginx/sbin/nginx -v #测试nginx访问是否正…

    技术杂谈 2023年7月11日
    0111
  • SpringBoot 多环境配置文件切换

    背景 很多时候,我们项目在开发环境和生成环境的环境配置是不一样的,例如,数据库配置,在开发的时候,我们一般用测试数据库,而在生产环境的时候,我们是用正式的数据,这时候,我们可以利用…

    技术杂谈 2023年7月11日
    0104
  • Rust入门秘籍(更新中)

    骏马金龙 (博客已搬家:www.junmajinlong.com) 网名骏马金龙,钟情于IT世界里的各种原理和实现机制,强迫症重症患者。爱研究、爱翻译、爱分享。特借此一亩三分田记录…

    技术杂谈 2023年5月31日
    0106
  • ps 创建文字模板的方法

    使用文字模板工具,注意不要使用移动工具移动选区,否则这样选区内的像素也会跟着移动,要使用选区工具移动和变换 Original: https://www.cnblogs.com/da…

    技术杂谈 2023年7月25日
    0111
  • 巴西针对电源产品的新法规

    巴西ANATEL近日发布了一项新的5159法案,该法案内容主要是关于移动电话使用的有线和无线电源和充电器。 法案称为《手机用充电器合格评定技术要求及测试程序》,涵盖了产品安全性和E…

    技术杂谈 2023年6月21日
    0102
  • 负负得正

    有了《系统架构的11条原则》,真正到设计阶段还有另外11个考虑。 系统正确性 考虑一:负负得正 假如我们看到某个代码,明显有逻辑错误,想随手改改。你就要考虑一件事情:这段明显有问题…

    技术杂谈 2023年5月31日
    0116
  • EducationalDPContest社论

    SoyTony 让我放歌词: Wish You Were Gay SoyTony 不让我放中文歌词, 《Wish You Were Gay》Baby, I don’t …

    技术杂谈 2023年7月24日
    057
  • 努力的去帮助他人

    天道运而无所积,故万物成;帝道运而无所积,故天下归;–庄子《天道篇》 知识分享才能成长,财富流动才能更多;努力的去帮助每一个人,自己也会收获更多的快乐;不要为生活琐事在…

    技术杂谈 2023年7月23日
    088
  • Go写文件的权限WriteFile(filename,data,0644)?

    本文来自博客园,作者:阿伟的博客,转载请注明原文链接:https://www.cnblogs.com/cenjw/p/go-ioutil-writefile-perm.html 前…

    技术杂谈 2023年7月24日
    094
  • 【工作记录】JDBC连接MySQL,跨时区调查CST转Asia/Shangha

    根据业务要求,不同的国家设置jvm参数,来确定当前时区。 // -Duser.timezone=Asia/Kolkata 印度&…

    技术杂谈 2023年7月10日
    091
  • 我为 Netty 贡献源码 | 且看 Netty 如何应对 TCP 连接的正常关闭,异常关闭,半关闭场景

    欢迎关注公众号:bin的技术小屋,本文图片加载不出来的话可查看公众号原文 本系列Netty源码解析文章基于 4.1.56.Final版本 写在前面….. 本文是笔者肉眼…

    技术杂谈 2023年7月11日
    082
  • k8s Service会话粘性

    Service资源还支持Session affinity(粘性会话活会话粘性)机制,它能够将来自同一个客户端的请求始终转发至同一个后端的Pod对象,这意味着它会影响调度算法的流量分…

    技术杂谈 2023年6月1日
    091
  • 8089汇编 标志寄存器

    8089汇编 标志寄存器 在8086CPU的指令集中,有的指令的执行是影响标志寄存器的,比如:add、sub、mul、div、inc、or、and等,它们大都是运算指令,进行逻辑或…

    技术杂谈 2023年6月1日
    0106
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球