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 {

  ...

  @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 不是那种我们在撸码中天天都会用到的解决方案,但在某些场景下它的确能够为我们扶危拯溺,雪中送炭!

感谢观赏,再会!😎

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Eplan】P8-图纸设计的四种方法

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 了解 EPLAN 的图纸设计的四种方法&#xff1a;面向图形、面向设备、面向物料清单、面向安装情况&#xff1b; 2、 问题场景 为什么 EPLAN 要使用四种不同的设计方法。 3、软硬件环境 1、软件版本&#xff1a;EPLAN…

Ubuntu无法安全地用该源进行更新,所以默认禁用该源。

解决方案 1. 获取并添加缺失的 GPG 公钥 可以使用 apt-key 命令来添加缺失的公钥。根据错误信息&#xff0c;缺失的公钥是 3B4FE6ACC0B21F32。 sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3B4FE6ACC0B21F322. 更新软件包列表 添加公钥后&#xff0c;更…

ADS131A04硬件设计与软件调试

一、IC基本信息 ADS131A0x 双通道或四通道 24 位 128kSPS 同步采样 Δ-Σ ADC •双通道或四通道同步采样差分输入 • 数据速率&#xff1a;高达 128kSPS • 高性能&#xff1a; – 单通道精度&#xff1a;在 10,000:1 动态范围内优于 0.1% – 有效分辨率&#xff1a;20.6位…

【MotionCap】搭建wsl2的pytorch环境

参考大神:wsl2-ubuntu版本 cuda下周cuda11.3 wget https://developer.download.nvidia.com/compute/cuda/11.3.0/local_installers/cuda_11.3.0_465.19.01_linux.run sudo sh cuda_11.3.0_465.19.01_linux.run cuda是开源的么?下15分钟

重磅!云起无垠荣获“智能模糊测试赛道领航者”等多项殊荣

近日&#xff0c;以 “新质•真能力”&#xff08;新质生产力&#xff0c;安全真能力&#xff09;为主题的第四届数字安全大会正式召开。在此次大会上&#xff0c;数世咨询发布了《中国数字安全产业年度报告(2024)》、新质百强榜单以及国内首本《数字安全蓝皮书》。这些报告和榜…

操作系统精选题(四)(论述题)

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;操作系统 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 前言 一、银行家算法的一道例题 二、页…

【NOI】C++程序设计入门四

文章目录 前言一、浮点型&#xff08;float和double&#xff09;1.float类型2.double类型 二、保留小数的方法方法一&#xff1a;方法二&#xff1a; 三、样题讲解问题1&#xff1a;1603. 冷饮的价格&#xff1f;问题2&#xff1a;1957. 求三个数的平均数问题3&#xff1a;1602…

爬数据是什么意思?

爬数据的意思是&#xff1a;通过网络爬虫程序来获取需要的网站上的内容信息&#xff0c;比如文字、视频、图片等数据。网络爬虫&#xff08;网页蜘蛛&#xff09;是一种按照一定的规则&#xff0c;自动的抓取万维网信息的程序或者脚本。 学习一些爬数据的知识有什么用呢&#x…

(PC+WAP)高端大气的装修装潢公司网站模板

(PCWAP)高端大气的装修装潢公司网站模板PbootCMS内核开发的网站模板&#xff0c;该模板适用于装修公司网站、装潢公司网站等企业&#xff0c;当然其他行业也可以做&#xff0c;只需要把文字图片换成其他行业的即可&#xff1b;(PCWAP)&#xff0c;同一个后台&#xff0c;数据即…

Vue2动态代理,换服务无须重启项目

1、痛点 当我们需要使用不同的服务器时&#xff0c;就需要手动修改vue.config.js中配置并重新启动项目。当项目越来越大时&#xff0c;会需要较长的时间来等待项目启动&#xff0c;如此反复&#xff0c;极大影响我们开发进度。 2、寻求解决方案 vue-cli 的代理是使用的http-p…

新勒索软件 Shinra 与 Limpopo 浮出水面

Shinra 勒索软件概览 Shinra 勒索软件的样本文件最早在 2024 年 4 月提交给公开的文件扫描服务。攻击者在部署和运行勒索软件前会先窃取受害者的数据&#xff0c;还会删除卷影副本以阻止数据恢复。 攻击者有时会使用亚文化的人物来进行命名&#xff0c;研究人员也怀疑 Shinra…

clion远程开发

clion远程开发 简要概括&#xff1a; 建立 SFTP 通讯&#xff0c;创建远程目录与本地目录的映射文件夹&#xff0c;就可以把本机文件夹中的文件用鼠标右键选中上全传&#xff0c;打开自动同步功能&#xff0c;后面更改文件就可以自动同步文件了。 一.新建SFTP远程链接服务 …

C++感受12-Hello Object 派生版

不变的功能&#xff0c;希望直接复用原有代码&#xff1b;变化的功能&#xff0c;希望在分开的代码里实现。 派生的基本概念和目的如何定义派生类以及创建派生对象派生对象的生死过程 0. 课堂视频 ff14-HelloObject-派生版 1. 派生的基本概念与目的 编程&#xff0c;或者说软…

无线领夹麦克风可以唱歌吗?推荐多款收音好的无线麦克风

如今是一个短视频营销飞速发展的时代&#xff0c;越来越多自媒体人通过短视频的方式来进行直播带货、生活Vlog、线上K歌等&#xff0c;记录下生活里那美丽的瞬间。不过也有不少新手视频创作者存在疑问&#xff1a;无线领夹麦克风可以唱歌吗&#xff1f; 答案是可以的&#xff0…

前端技术(二)——javasctipt 介绍

一、javascript基础 1. javascript简介 ⑴ javascript的起源 ⑵ javascript 简史 ⑶ javascript发展的时间线 ⑷ javascript的实现 ⑸ js第一个代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>…

SSM“点点通”餐饮点餐小程序-计算机毕业设计源码11264

摘要 随着中国经济的飞速增长&#xff0c;消费者的智能化水平不断提高&#xff0c;许多智能手机和相关的软件正在得到更多的关注和支持。其中&#xff0c;微信的餐饮点餐小程序更是深得消费者的喜爱&#xff0c;它的出现极大地改善了消费者的生活质量&#xff0c;同时&#xf…

电商价格监测:品牌控价维权的关键利器

品牌在进行控价时&#xff0c;所面对的是线上成千上万条的商品链接&#xff0c;如果仅依靠人工&#xff0c;根本无法做到准确且全面地完成电商价格监测工作。因此&#xff0c;一套准确率高的电商价格监测系统对于品牌的控价维权而言&#xff0c;其重要性不言而喻。 在形形色色的…

昇思25天学习打卡营第八天|保存与加载

背景 提供免费算力支持&#xff0c;有交流群有值班教师答疑的华为昇思训练营进入第八天了。 今天是第八天&#xff0c;前七天的学习内容可以看链接 昇思25天学习打卡营第一天|快速入门 昇思25天学习打卡营第二天|张量 Tensor 昇思25天学习打卡营第三天|数据集Dataset 昇思25天…

GPT-5:下一代AI如何彻底改变我们的未来

GPT-5 发布前瞻&#xff1a;技术突破与未来展望 随着科技的飞速发展&#xff0c;人工智能领域不断迎来新的突破。根据最新消息&#xff0c;OpenAI 的首席技术官米拉穆拉蒂在一次采访中确认&#xff0c;GPT-5 将在一年半后发布&#xff0c;并描述了其从 GPT-4 到 GPT-5 的飞跃如…

分布式限流:Spring Cloud Gateway 限流

分布式限流&#xff1a;Spring Cloud Gateway 限流 在现代微服务架构中&#xff0c;流量控制是一个至关重要的部分。分布式限流作为一种有效的流量控制手段&#xff0c;能够帮助我们保护系统不被突发的流量冲垮。Spring Cloud Gateway支持多种限流方式。 什么是分布式限流 分…