Swift 新结构化并发中鲜为人知的 isolated 参数

news2024/11/20 10:37:01

在这里插入图片描述

概述

伴随着 Swift 5.5(WWDC21)推出的新结构化并发到今年的 WWDC 24 已经有 3 个多年头了。想必大家都对其中 async/awiat、async let、TaskGroup、Actor 等各种概念都了然于胸了吧?

不过小伙伴们可能不知道的是:新结构化并发(或叫现代结构化并发)中还有一个“隐藏宝藏”,它就是 isolated 参数。

在本篇博文中,您将学到如下内容:

  • 概述
  • 1. isolated 参数(isolated parameters)简介
  • 2. isolated parameters 的作用
  • 3. isolated parameters 的应用场景
  • 总结

Swift 现代结构化并发中 isolated parameters 的存在对于某些应用场景有着不可或缺的重要意义!不信?且看分晓!

Let‘s go!!!😉


1. isolated 参数(isolated parameters)简介

在 Swift 5.5 新并发模型中有一个 isolated parameters 的概念。它很好理解:isolated 其实是一个关键字,isolated 可以用在修饰方法或闭包的参数上。

空说无凭,撸码为证!

在下面的代码中我们将 isolated 关键字应用在了 run 方法的 god 参数上:

actor GodActor {}

func run(_ god: isolated GodActor) {}

与此类似,isolated 关键字同样可以应用在闭包中的参数上:

actor GodActor {
    func handler<R>(
        _ action: @Sendable (_ god: isolated GodActor) throws -> R
    ) rethrows -> R {
        try action(self)
    }
}

值得注意的是:isolated 关键字修饰的参数类型必须是一个 Actor。

在这里插入图片描述

如果违反这一条,编译器就会立即毫不留情的“勃然大怒”:

‘isolated’ parameter type ‘Int’ does not conform to ‘Actor’ or ‘DistributedActor’

在了解 isolated parameters 的用法之后,满腹狐疑的小伙伴们肯定要问了:那么它到底是干嘛滴的呢?

2. isolated parameters 的作用

isolated 参数的作用非常简单:无论它被用来修饰方法或是闭包中的 Actor 参数,都意味着该方法或闭包在运行时都会限定在此 Actor 所在的上下文中。

An isolated parameter means the function runs on whatever actor is passed in.

所以任何方法或闭包都只能有一个被 isolated 修饰的 Actor 参数,否则天知道它要被用在哪个 Actor 上了。

还拿之前的 run() 方法来说,它有点像下面代码的意思:

extension MyActor {
    func run() { ... }
}

不过,包含 isolated 参数方法的重要意义在于:我们可以将特定 Actor 的同步上下文传递到任何方法或闭包的执行中去了。

不知小伙伴们发现了没有,上面包含 isolated 参数的 run() 或 handler() 方法本身都没有再被 async 所修饰,这是有意而为之的!因为像其它异步并发隔离(isolation)一样,它们在调用时要不要加上 await 关键字取决于当时的执行语境。


这有点像某种“隐式异步”方法。更多关于“隐式异步”方法的介绍请小伙伴们移步如下链接观赏精彩的内容:

  • Swift 警惕“隐式异步(implicitly asynchronous)”方法的执行陷阱

说了上面这么一大堆,可能有的小伙伴还是搞不清 isolated 参数存在的真谛吧?

别急,下面我们就用一个活灵活现的例子让大家彻底茅塞顿开!

3. isolated parameters 的应用场景

假设我们要绕过 CoreData 直接写一个 SQLite 数据库的包装器。

我们会用该包装器来执行 SQLite 数据库中的一些 SQL 命令,比如查询、插入、修改和删除等等。为了处理好数据库操作中的同步问题,我们新创建一个 Connection Actor 来排忧解难:

public actor Connection {
	public func execute(_ query: String) throws {
		//...
	}
}

比如,当我们想向数据库中插入对象时可以这么写:

let conn = Connection()
await conn.execute("INSERT INTO table1 VALUES ('a', 'b', 'c')")

但是,随后我们可能发现每次执行单个 SQL 语句是效率极其低下的,我们更希望能够以“原子的”方式一次性执行多条 SQL 语句。

所谓以“原子的”方式意思是:

  • 要么所有 SQL 语句都执行成功,数据库被正确更新;
  • 若其中有任何一条 SQL 语句出错,那么就好像所有语句都没有被执行一样——数据库保持原封不动;

这种以“原子的”执行方式称为事务(Transactions),SQLite 数据库或任何其它现代数据库都对其提供了更好的支持。我们利用这一点可以很轻松的在 Connection 中实现一个 transaction 方法来“拔刀相助”:

public actor Connection {

  ...

  @discardableResult
  func transaction<R>(
    _ action: @Sendable (_ connection: isolated Connection) throws -> R
  ) throws -> R {
    try execute("BEGIN TRANSACTION")
    do {
      let result = try action(self)
      try execute("COMMIT TRANSACTION")
      return result
    } catch {
      try execute("ROLLBACK TRANSACTION")
      throw error
    }
  }
}

现在,我们可以这样调用 transaction 方法来实现 SQLite 包装器对事务的支持了:

let conn = Connection()
conn.transaction { 
  $0.execute("INSERT INTO table1 VALUES ('a', 'b', 'c')")
  $0.execute("INSERT INTO table2 VALUES ('d', 'e', 'f')")
}

可能眼尖的小伙伴们已经发现了:上面 transaction 方法闭包中的 connection 参数是被 isolated 关键字所修饰着的。

按照之前的解释,这说明 transaction 方法闭包会在 connection Actor 的上下文中执行,它由此引来的重要推论是:transaction 闭包中所有代码的执行都不会被打断!

这一点非常关键!

如果我们不用 isolated 来修饰 transaction 方法闭包中的 connection 参数,那么它就会是下面这个样子:

public actor Connection {

  ...

  @discardableResult
  func transaction<R>(
    _ action: @Sendable (_ connection: Connection) async throws -> R
  ) throws -> R {
    ...
  }
}

connection.transaction { 
  await $0.execute("INSERT INTO table1 VALUES ('a', 'b', 'c')")
  await $0.execute("INSERT INTO table2 VALUES ('d', 'e', 'f')")
}

如上代码所示,现在 transaction 方法中的闭包必须被 async 所修饰,这带来的直接后果就是:其内部的所有 execute() 方法的调用前面都要加上 await 关键字!

回忆一下,任何用 await 关键字所修饰方法的执行都有可能被挂起!大家知道在并发执行中挂起意味着指令流可能会被打断,从而引起重入(Reentrancy)问题。


重入问题会导致隔离一致性被打破。更多关于 Actor 重入问题的讨论请小伙伴们移步如下链接观赏:

  • 深入理解 Swift 新并发模型中 Actor 的重入(Reentrancy)问题

回到上面的例子,执行用 await 修饰的两条 execute() 方法是非常危险的!因为这可能会导致我们的事务执行到一半被挂起(suspend),如果此时相同的 Connection 对象中有另一个任务开始执行就会发生嵌套(nested)事务的错误(在调用 COMMIT TRANSACTION / ROLLBACK TRANSACTION 之前又调用了 BEGIN TRANSACTION)。

而使用 isolated 关键字则恰恰可以避免这种情况!因为这时 transaction 方法中任何与 Connection 相关方法的调用都无需用 await 修饰,从而不会发生潜在的挂起行为。

这就是 isolated parameters 存在的真谛啊!棒棒哒!


更多关于 Swift 新结构化并发中同步问题的例子,请小伙伴们到下面的博文中观赏精彩的内容:

  • SwiftUI async/await 并发代码提示 Non-sendable type cannot cross actor boundary 警告的解决
  • Swift新async/await并发中利用Task防止指定代码片段执行的数据竞争(Data Race)问题

总结

在本篇博文中,我们介绍了 Swift 现代并发模型中少有人知的 isolated parameters 机制,并用了一个非常通俗易懂的“栗子”让大家豁然开朗!

虽然 isolated parameters 不是那种我们在撸码中天天都会用到的解决方案,但在某些场景下它的确能够为我们扶危拯溺,雪中送炭!

感谢观赏,再会!😎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1881766.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

零基础STM32单片机编程入门(五)FreeRTOS实时操作系统详解及实战含源码视频

文章目录 一.概要二.什么是实时操作系统三.FreeRTOS的特性四.FreeRTOS的任务详解1.任务函数定义2.任务的创建3.任务的调度原理 五.CubeMX配置一个FreeRTOS例程1.硬件准备2.创建工程3.调试FreeRTOS任务调度 六.CubeMX工程源代码下载七.讲解视频链接地址八.小结 一.概要 FreeRTO…

世界羽坛失去了一位天才选手:如何预防运动场上发生意外

世界羽坛失去了一位天才选手&#xff1a;如何预防运动场上发生意外 --中国羽毛球新星张志杰赛场突发意外&#xff0c;年仅17岁离世 中国羽毛球界的一颗新星、年仅17岁的张志杰&#xff0c;在印尼举行的2024亚洲青年羽毛球锦标赛中不幸离世。这位出生于嘉兴的天才选手&#xf…

北京酒店订房小程序开发的优势与主要功能

随着我国经济与交通的飞速发展&#xff0c;人们出行的次数越来越多&#xff0c;频率也越来越快。无论是出差还是出游&#xff0c;人家对外出酒店的舒适度与便捷度的要求也越来越高。为了满足人们对于酒店的新需求&#xff0c;北京酒店订房小程序与互联网技术相结合&#xff0c;…

经典文献阅读之--BALM2(高效且一致的激光雷达点云束调整)

0. 简介 束调整&#xff08;Bundle Adjustment&#xff0c;BA&#xff09;是指同时确定传感器姿态和场景几何的问题&#xff0c;这是机器人视觉中的一个基本问题。本文提出了一种高效且一致的激光雷达束调整方法。该方法利用边缘和平面特征来表示场景几何&#xff0c;并直接最…

制定全面测试计划:使用TS-GNSS模拟器助力接收器选择

GPS/GNSS信号无处不在&#xff0c;也是目前定位导航应用中最为关键的一环&#xff0c;而GNSS接收器芯片组的低成本和高性能使得将GNSS接收器更容易得集成到以前从未有过的产品中去。由于存在以多种频率传输信号的多个GNSS星座&#xff0c;以及用于提高GNSS精度的各种可用技术&a…

并发控制-事务的调度、数据不一致问题(更新丢失、脏读、不可重复读)、非串行调度的的可串行化

一、引言 1、数据库管理系统DBMS的事务处理技术实现的另一个主要功能部分是并发控制机制。并发控制机制完成的功能就是对并发执行的事务进行控制&#xff0c;保证事务的隔离性&#xff0c;从而进一步保持数据库的一致性。 2、事务的并发控制就是对并发执行的不同事务中的数据…

NLP特征提取的惊人历史演变

NLP特征提取的惊人演变 1.理解特征提取2. 文本表示的演变2.1.词袋的简单性2.2. N-Gram 模型的进步2.3. TF-IDF 的崛起 3. 深入研究词嵌入3.1.探索 Word2Vec3.2.深入了解 GloVe3.3.深入研究 FastText 4. 上下文嵌入的影响4.1 ELMo 的突破4.2 理解 BERT 的机制4.3 Transformer的出…

MySQL-核心知识要点

1、索引的数据结构-Btree BTree的优势&#xff1a; B树的内节点无data&#xff0c;一个节点可以存储更多的K-V对。在构造树时&#xff0c;需要的内节点会更少&#xff0c;那么树的层级也会越低。查询一条数据时&#xff0c;1. 扫描的层级低&#xff0c;扫描过的节点更少&…

Java使用Tessdata做OCR图片文字识别【搬代码】

下载tessdata各语言集合包.zip 找个盘下面解压缩&#xff0c;名字改成英文的 pom文件依赖 <dependency><groupId>net.sourceforge.tess4j</groupId><artifactId>tess4j</artifactId><version>4.5.4</version></dependency>j…

第二天:ALOAM前端讲解【第2部分】

三、scan2scan 3. 帧间匹配 特征关联与损失函数计算 (1)线特征 点到线的距离公式: d ϵ = ∣ ( X ~ ( k +

高温电子设备对设计和可靠性带来挑战

1 高温应用 地下石油和天然气行业&#xff0c;温度&#xff1e;150℃&#xff0c;最高温度可达200℃。 地下钻探作业 地下钻探时&#xff0c;需要收集周围的地质构造&#xff0c;可通过测量电阻率、放射性、声音传播时间、磁共振和其他属性&#xff0c;同时还会监控压力、温度、…

[go-zero] goctl 生成api和rpc

文章目录 1.goctl 概述2.go-zero 需要安装的组件3.生成 api4.生成 rpc 1.goctl 概述 goctl支持多种rpc&#xff0c;较为流行的是google开源的grpc&#xff0c;这里主要介绍goctl rpc protoc的代码生成与使用。protoc是grpc的命令&#xff0c;作用是将proto buffer文件转化为相…

2024.07使用gradle上传maven组件到central.sonatype,非常简单

本文基于sonatypeUploader2.0版本 在1.0版本我们还需要手动去添加maven-publish和signing插件&#xff0c;在2.0版本他已经内置了&#xff0c;如果你仍然需要手动配置&#xff0c;你可以手动添加这两个插件及逻辑。 具体信息参考开源仓库&#xff1a; 插件仓库&#xff1a;h…

GPT-5:博士级智能的破晓,人工智能的新里程碑

随着科技的飞速发展&#xff0c;人工智能领域再次迎来了一场革命性的突破。备受瞩目的新一代大语言模型GPT-5即将在一年半之后发布&#xff0c;这一创新不仅将再次刷新人们对人工智能的认知&#xff0c;更有可能在多个领域展现出超越人类博士级智能的卓越能力。本文将对GPT-5的…

一体化导航的优点及应用领域

一体化导航&#xff0c;作为现代导航技术的重要发展方向&#xff0c;正日益展现出其独特的魅力和广泛的应用前景。这种导航方式将多种导航技术、信息系统以及数据处理方法集成于一个统一的平台上&#xff0c;为用户提供高效、准确、便捷的导航服务。 一体化导航的核心在于其高度…

【Python】从基础到进阶(二):了解Python语言基础以及数据类型转换、基础输入输出

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、引言二、基本数据类型转换1. 隐式转换2. 显式转换 三、基本输入输出1. 输入&#xff08;input&#xff09;2. 输出&#xff08;print&#xff09;3. 案例&#xff1a;输入姓名、年龄、身高以及体重&#xff0c;计算BMI指…

onnx文件QNN部署

一、准备环境 1.linux配置qnn sdk &#xff08;1&#xff09;下载qnn sdk https://qpm.qualcomm.com/#/main/tools/details/qualcomm_ai_engine_direct &#xff08;2&#xff09;下载qpm3 https://softwarecenter.qualcomm.com/#/catalog/item/3097f479-8993-11ea-9571-06…

Luminar Neo 1.20.0 (macOS Universal) - 创新 AI 图像编辑器

Luminar Neo 1.20.0 (macOS Universal) - 创新 AI 图像编辑器 利用尖端的人工智能生成技术&#xff0c;轻松增强照片效果 请访问原文链接&#xff1a;https://sysin.org/blog/luminar-neo/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1…

揭秘Wish自养号秘诀:新手卖家如何快速出单?

对于卖家来说&#xff0c;如果想要提升店铺的转化率和销量&#xff0c;有几个关键策略是必不可少的&#xff1a; 一、精心挑选热销产品 成功的第一步在于选品。选择热销产品如同掌握了成功的钥匙。卖家需要深入分析平台用户群体&#xff0c;了解他们的需求和偏好。例如&#…

Powershell 简易爬虫,提取种子网站的磁力链接

目录 一. 需求二. 分析2.1 思路分析2.2 技术点 三. 代码四. 效果 一. 需求 ⏹有网站如下所示&#xff0c;先要求从按照关键词搜索到的网页中&#xff0c;提取出所有的磁力链接。 二. 分析 2.1 思路分析 打开网页之后&#xff0c;从网页中先提取出所有的标题相关的url然后再打…