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

在这里插入图片描述

概述

伴随着 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 {...@discardableResultfunc 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 {...@discardableResultfunc 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.mzph.cn/pingmian/38488.shtml

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

相关文章

骑行十里箐:风景,挑战与心灵,在幽谷中的协奏曲

2024年6月29日&#xff0c;星期六&#xff0c;一个看似平凡的日子&#xff0c;却因一次不同寻常的骑行而变得难以忘怀。作为校长骑行群的一员&#xff0c;我有幸参加了这次骑行十里箐的活动。从滇池后海的宁静开始&#xff0c;到宝珠山顶的壮观落幕&#xff0c;这一天的旅程充满…

ABeam×StartUp | ABeam德硕中国新创部门拜访通用机器人初创公司 :逐际动力,就具身智能机器人的发展展开交流

近日&#xff0c;ABeam中国新创部门有幸拜访了深圳逐际动力科技有限公司&#xff08;以下简称&#xff1a;逐际动力&#xff09;。作为一家通用机器人公司&#xff0c;其在人形机器人、四轮足机器人等领域具有深厚的学术与技术储备。 现场合影 左&#xff1a;ABeam中国新创部门…

Python | Leetcode Python题解之第201题数字范围按位与

题目&#xff1a; 题解&#xff1a; class Solution:def rangeBitwiseAnd(self, m: int, n: int) -> int:while m < n:# 抹去最右边的 1n n & (n - 1)return n

sheng的学习笔记-hive框架原理

需要学习的前置知识&#xff1a;hadoop 可参考 sheng的学习笔记-hadoop-CSDN博客 相关网址 官网&#xff1a;http://hive.apache.org 文档&#xff1a;https://cwiki.apache.org/confluence/display/Hive/GettingStarted https://cwiki.apache.org/confluence/display/Hive/…

Sermant自定义插件开发上手体验

作者&#xff1a;用友汽车信息科技&#xff08;上海&#xff09;有限公司 刘亚洲 Java研发工程师 一、研究缘由 由于目前我们所处的行业是汽车行业&#xff0c;项目上进行云服务的迁移时使用到了Sermant中的相关插件, 为了加深对Sermant开发和运行机制的了解&#xff0c;我…

线程、线程池与CompletableFuture线程编排

线程、线程池与CompletableFuture线程编排 1. 多线程的初始化方式1.1 简单实现多线程的启动方式(3种)1. 继承Thread实现2. 实现Runnable接口3. 实现callable接口(返回值)2. 基于线程池实现多线程的启动方式❤❤❤2.1 线程池创建与使用2.2 SpringBoot自定义线程池组件 ❤ ❤3. 多…

如何屏幕录制?这3款软件轻松实现!

随着科技的不断发展&#xff0c;屏幕录制成为了人们日常生活中越来越常见的需求。无论是录制游戏过程、分享教程、还是保存重要的在线会议&#xff0c;屏幕录制都是一个非常实用的工具。然而&#xff0c;很多用户却不知道如何屏幕录制。本文将详细介绍3款屏幕录制软件&#xff…

《梦醒蝶飞:释放Excel函数与公式的力量》7.3 RIGHT函数

第七章&#xff1a;文本处理函数 第三节&#xff1a;7.3 RIGHT函数 7.3.1. RIGHT函数简介 RIGHT函数用于从文本字符串的末尾提取指定数量的字符&#xff0c;适合在需要从文本中提取特定后缀或处理固定格式的数据时使用。 语法&#xff1a; RIGHT(text, [num_chars]) text…

探索ChatGPT是如何改变癌症护理

了解生成式人工智能&#xff08;尤其是 ChatGPT&#xff09;如何通过高级数据集成和个性化患者管理来增强诊断和治疗&#xff0c;从而改变癌症治疗。了解 Color Health 的创新副驾驶模型及其对早期检测和患者结果的影响。 近年来&#xff0c;人工智能与医疗保健的融合为癌症治疗…

机器学习中的数学底蕴与设计模式

在说机器学习设计模式之前&#xff0c;想多说几句&#xff0c;在进入软件行业最初的10年&#xff0c;那时候耳熟能详的基本就是多线程编程&#xff0c;互斥同步锁&#xff0c;设计模式&#xff0c;OOA&#xff0c;OOP&#xff0c;常规数组&#xff0c;tree&#xff0c;图的数据…

体验升级:扫描全能王智能高清滤镜2.0全面测评

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

【CT】LeetCode手撕—19. 删除链表的倒数第 N 个结点

题目 原题连接&#xff1a;19. 删除链表的倒数第 N 个结点 1- 思路 模式识别&#xff1a;删除倒数第 n 个结点 ——> 定义 dummyHead 并用双指针实现删除逻辑 2- 实现 ⭐19. 删除链表的倒数第 N 个结点——题解思路 class Solution {public ListNode removeNthFromEnd(Li…

React-Native优质开源项目

React Native 是一个由 Facebook 开发的开源框架&#xff0c;允许开发者使用 JavaScript 和 React 来构建原生移动应用。它允许开发者编写一次代码&#xff0c;然后可以在 iOS 和 Android 平台上运行&#xff0c;而无需为每个平台单独编写代码。以下是 React Native 的一些关键…

MySQL 高级SQL高级语句(二)

一.CREATE VIEW 视图 可以被当作是虚拟表或存储查询。 视图跟表格的不同是&#xff0c;表格中有实际储存数据记录&#xff0c;而视图是建立在表格之上的一个架构&#xff0c;它本身并不实际储存数据记录。 临时表在用户退出或同数据库的连接断开后就自动消失了&#xff0c;而…

LLM学习记录

概述 语言模型经历过四个阶段的发展&#xff0c;依次从统计语言模型到神经网络语言模型&#xff08;NLM&#xff09;&#xff0c;到出现以 BERT 和 Transformer 架构为代表的预训练语言模型&#xff08;PLM&#xff09;&#xff0c;最终到大型语言模型阶段&#xff08;LLM&…

数学建模比赛介绍与写作建议

0 小序 本文的写作起因是导师要求我给打算参加相关竞赛的师弟们做一次讲座和汇报。我梳理了一个ppt提纲&#xff0c;并经过整理&#xff0c;因此有了这篇文章。 我打算从数学建模论文写作格式和写作技巧入手&#xff0c;接着介绍数学建模常用的数学模型&#xff0c;最后提出一…

【数据结构(邓俊辉)学习笔记】二叉搜索树04——AVL树

文章目录 1.重平衡1.1 AVL BBST1.2 平衡因子1.3 适度平衡1.4 接口1.5 失衡 复衡 2. 插入2.1 单旋2.2 双旋2.3 实现 3. 删除3.1 单旋3.2 双旋3.3 实现 4. &#xff08;3 4&#xff09;-重构4.1 "34"重构4.2 "34"实现4.3 rotateAt4.4 综合评价 1.重平衡 1…

【Python】利用代理IP爬取当当网数据做数据分析

前言 在数字化浪潮的推动下&#xff0c;电商平台已经彻底改变了我们的购物方式。从简单的在线交易到复杂的用户交互&#xff0c;电商平台积累了海量的用户数据。这些数据&#xff0c;如同隐藏在深海中的宝藏&#xff0c;等待着被发掘和利用。通过分析用户的浏览、搜索、购买等行…

(4.2)Sourcegraph(Chrome插件)——github实现源码阅读

一、下载 下载方式参考&#xff1a;如何安装 Chrome 插件&#xff1f;以 Show_Rank 为例 下载链接一&#xff1a;从Chrome应用商店直接搜索&#xff0c;https://chromewebstore.google.com/detail/sourcegraph/dgjhfomjieaadpoljlnidmbgkdffpack?utm_sourceext_app_menu 如…

可燃气体报警器检测周期:企业安全管理体系中的关键环节

可燃气体报警器作为现代工业安全监测的重要工具&#xff0c;对于预防火灾、爆炸等安全事故起着至关重要的作用。 而检测周期的设置&#xff0c;直接关系到报警器的准确性和可靠性。 接下来&#xff0c;佰德将深入探讨可燃气体报警器检测周期的重要性&#xff0c;并通过案例分…