Swift Concurrency(并发)学习

news2025/1/8 12:09:09

Swift 的并发模型是基于 异步任务任务调度 的一套现代化的异步编程工具。以下是相关语法规则总结


1. 异步函数(async)与 await

  • async 用于声明一个异步函数,表示函数可能会执行耗时任务,例如网络请求、文件读写等。
  • 在调用异步函数时,使用 await 关键字等待函数返回结果。

示例

func fetchUserID(from server: String) async -> Int {
    if server == "primary" {
        return 97
    }
    return 501
}
  • async 声明: 表示 fetchUserID 是异步函数。
  • 返回值类型: async 函数支持返回值,格式为 async -> ReturnType
  • 在异步函数内部,可以通过一些耗时操作(如网络请求)返回结果。

调用异步函数

func fetchUsername(from server: String) async -> String {
    let userID = await fetchUserID(from: server) // 用 await 调用异步函数
    if userID == 501 {
        return "John Appleseed"
    }
    return "Guest"
}
  • await 关键字: 调用异步函数时需要等待其执行完成。
  • 通过 await,程序会暂停当前任务,直到异步函数返回结果。

2. 使用 async let 实现并发任务

  • 如果多个异步任务之间互不依赖,可以用 async let 并发地执行它们。
  • async let 启动的任务是并发运行的,但当你使用返回值时需要用 await

示例

func connectUser(to server: String) async {
    async let userID = fetchUserID(from: server) // 异步获取 userID
    async let username = fetchUsername(from: server) // 异步获取 username

    // 等待两个任务完成,合并结果
    let greeting = await "Hello \(username), user ID \(userID)"
    print(greeting)
}
  • async let 声明异步任务,让它们同时运行。
  • await 当需要用返回值时才等待任务完成。
  • 并发执行可以显著提升性能,尤其在多个任务需要执行时。

3. 使用 Task 从同步代码中调用异步函数

  • 如果当前代码是同步上下文(比如普通函数或全局代码),可以用 Task 调用异步函数。

示例

Task {
    await connectUser(to: "primary")
}
// 输出:Hello Guest, user ID 97
  • Task 一个封装异步代码的上下文,它不会阻塞当前线程。
  • 执行顺序: Task 会在后台运行,不会阻塞主线程。

4. 使用 TaskGroup 进行任务分组

  • TaskGroup 是 Swift 的一种工具,用于管理一组并发任务。
  • 使用任务分组时,可以动态添加任务并收集任务结果。

示例

let userIDs = await withTaskGroup(of: Int.self) { group in
    for server in ["primary", "secondary", "development"] {
        group.addTask {
            return await fetchUserID(from: server)
        }
    }

    var results: [Int] = []
    for await result in group {
        results.append(result)
    }
    return results
}
  • withTaskGroup 创建一个任务组。
  • group.addTask 动态向任务组中添加任务。
  • for await 异步地收集任务结果。
输出:

假设 fetchUserID 返回的结果为 [97, 501, 97],最终的 userIDs[97, 501, 97]


5. Actor

  • Actor 是 Swift 提供的一种结构,保证并发访问的安全性。
  • 与类(class)类似,actor 也可以包含属性和方法。
  • 区别:
    • Actor 是并发安全的:它会序列化对其属性的访问,避免数据竞争。
    • 在调用 Actor 的方法或访问属性时,必须使用 await

示例

actor ServerConnection {
    var server: String = "primary"
    private var activeUsers: [Int] = []

    func connect() async -> Int {
        let userID = await fetchUserID(from: server)
        activeUsers.append(userID)
        return userID
    }
}

let server = ServerConnection()
let userID = await server.connect()
  • Actor 的特点:
    • ServerConnection 中的 serveractiveUsers 属性只能通过 Actor 内部的方法访问。
    • 调用 connect 方法时必须用 await,因为它可能涉及异步操作。

6. 重要语法总结

  1. asyncawait
    • 用于声明和调用异步函数。
    • 异步函数可以暂停当前任务,等待其他任务完成。
  2. async let
    • 并发地启动多个异步任务,但只在需要时等待结果。
  3. Task
    • 用于从同步代码中调用异步函数。
  4. TaskGroup
    • 管理多个并发任务,并收集它们的结果。
  5. Actor:
    • 确保对共享状态的并发访问是安全的。

7. 拓展知识

Swift 的并发功能建立在底层 GCD(Grand Central Dispatch)Swift Concurrency Runtime 之上,以下是一些拓展知识:

7.1 串行队列 vs 并发队列

  • 串行队列: 一个任务完成后才开始下一个任务。
  • 并发队列: 多个任务同时运行,但完成顺序不保证。

7.2 异步序列和迭代

Swift 支持 异步序列(AsyncSequence,可以异步地遍历序列:

struct Counter: AsyncSequence {
    typealias Element = Int
    let end: Int

    func makeAsyncIterator() -> AsyncIterator {
        return AsyncIterator(end: end)
    }

    struct AsyncIterator: AsyncIteratorProtocol {
        let end: Int
        var current = 0

        mutating func next() async -> Int? {
            current += 1
            return current <= end ? current : nil
        }
    }
}

for await number in Counter(end: 5) {
    print(number)
}
// 输出:1 2 3 4 5

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

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

相关文章

PHP框架+gatewayworker实现在线1对1聊天--接收消息(7)

文章目录 接收消息的原理接收消息JavaScript代码 接收消息的原理 接收消息&#xff0c;就是接受服务器转发的客户端消息。并不需要单独创建函数&#xff0c;因为 ws.onmessage会自动接收消息。我们需要在这个函数里进行处理。因为初始化的时候&#xff0c;已经处理的init类型的…

当算法遇到线性代数(四):奇异值分解(SVD)

SVD分解的理论与应用 线性代数系列相关文章&#xff08;置顶&#xff09; 1.当算法遇到线性代数&#xff08;一&#xff09;&#xff1a;二次型和矩阵正定的意义 2.当算法遇到线性代数&#xff08;二&#xff09;&#xff1a;矩阵特征值的意义 3.当算法遇到线性代数&#xff0…

科研绘图系列:R语言科研绘图之标记热图(heatmap)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍加载R包数据下载导入数据数据预处理画图系统信息参考介绍 科研绘图系列:R语言科研绘图之标记热图(heatmap) 加载R包 library(tidyverse) library(ggplot2) library(reshape)…

Mysql--基础篇--SQL(DDL,DML,窗口函数,CET,视图,存储过程,触发器等)

SQL&#xff08;Structured Query Language&#xff0c;结构化查询语言&#xff09;是用于管理和操作关系型数据库的标准语言。它允许用户定义、查询、更新和管理数据库中的数据。SQL是一种声明性语言&#xff0c;用户只需要指定想要执行的操作&#xff0c;而不需要详细说明如何…

Excel重新踩坑5:二级下拉列表制作;★数据透视表;

0、在excel中函数公式不仅可以写在单元格里面&#xff0c;还可以写在公式里面。 1、二级下拉列表制作&#xff1a; 2、数据透视表&#xff1a; 概念&#xff1a;通过拖拉就能实现复杂函数才能实现的数据统计问题。 概览&#xff1a;在插入选项中有个数据透视表&#xff0c;数…

Linux-----进程处理(waitpid,进程树,孤儿进程)

目录 waitpid等待 进程树 孤儿进程 waitpid等待 Linux中父进程除了可以启动子进程&#xff0c;还要负责回收子进程的状态。如果子进程结束后父进程没有正常回收&#xff0c;那么子进程就会变成一个僵尸进程——即程序执行完成&#xff0c;但是进程没有完全结束&#xff0c;其…

解决报错net.sf.jsqlparser.statement.select.SelectBody

在我们项目集成mybatis-plus时,总会遇到奇奇怪怪的报错,比如说下面的这个报错 而这个报错,是告诉我们的分页依赖冲突,要加个jsqlparser依赖来解决这个冲突,也相当于平衡,但是可能因为我们版本的不匹配,还是会报错,例如下面这样 但是我们是不知道到底是什么依赖冲突的,这个时候就…

感知器的那些事

感知器的那些事 历史背景Rosenblatt和Minsky关于感知机的争论弗兰克罗森布拉特简介提出感知器算法Mark I感知机争议与分歧马文明斯基简介单层感知器工作原理训练过程多层感知器工作原理单层感知机 vs 多层感知机感知器模型(Perceptron),是由心理学家Frank Rosenblatt在1957年…

内核链表 例题 C语言实现

问题&#xff1a; 将下面的数据节点信息转换为链表结构&#xff0c;并遍历输出。要求根据type的值来决定val的类型。 type为1代表bool类型&#xff0c;2代表整形&#xff0c;3代表浮点型。无需解析文本&#xff0c;直接赋值形成节点即可。 代码&#xff1a; list.c #includ…

C语言结构体数组

上次我们讲解了结构体&#xff0c;这里还有高级应用就是结构体数组&#xff08;集合的集合&#xff09; &#xff08;这里提醒一句&#xff0c;想要在北京参加NCRE考试的朋友们今天开始报名了&#xff09; 定义 还是拿上回那个学生数据的结构体 typedef struct {int year;i…

深入了解 ES6 Map:用法与实践

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

在Vue3项目中使用svg-sprite-loader

1.普通的svg图片使用方式 1.1 路径引入 正常我们会把项目中的静态资源放在指定的一个目录&#xff0c;例如assets,使用起来就像 <img src"../assets/svgicons/about.svg" /> 1.2封装组件使用 显然上面的这种方法在项目开发中不太适用&#xff0c;每次都需…

谷歌SEO真的需要很长时间吗?

关键在于策略与执行力&#xff0c;很多人在刚开始做谷歌SEO时&#xff0c;都会产生一种挫败感&#xff0c;觉得排名变化太慢&#xff0c;看不到显著效果。这其实是因为SEO本身是一项需要时间的工作&#xff0c;特别是在竞争激烈的领域。但如果策略得当、执行力强&#xff0c;时…

耐高压26V输入5V升压充电8.4V芯片

HU6877作为一款集成了26V高耐压保护的5V升压至8.4V两节锂电池充电管理IC&#xff0c;凭借其高效升压、智能充电管理、多重安全保护及高耐压特性&#xff0c;在高端手电筒、便携式医疗设备、无人机等领域展现出了广泛的应用前景。本文将详细探讨HU6877的技术特点、工作原理、应用…

linuxCNC(六)配置LinuxCNC完成伺服控制

这里写目录标题 1、 cia402安装2、找伺服描述文件&#xff08;xml&#xff09;3、配置ethercat-config.xml3.1、打开hal-cia402/example/ethercat-conf.xml3.2、修改 ethercat-conf.xml文件中vid"0x000116c7" pid"0x003e0402"3.3、其他参数&#xff0c;根据…

【数据结构】链表(2):双向链表和双向循环链表

双向链表&#xff08;Doubly Linked List&#xff09; 定义&#xff1a; 每个节点包含三个部分&#xff1a; 数据域。前驱指针域&#xff08;指向前一个节点&#xff09;。后继指针域&#xff08;指向下一个节点&#xff09;。 支持从任意节点向前或向后遍历。 #define dat…

指针 const 的组合

1、首先来了解一下常量 const int num 5&#xff1b; 那么num的值是5&#xff0c; num的值不可修改 2、来了解一下指针 int value 5; int* p &value; 我喜欢吧指针和类型放一起&#xff0c;来强调p是一个指针类型&#xff0c; 而赋值的时候就得赋值一个int类型的地址…

Tableau数据可视化与仪表盘搭建-数据可视化原理

目录 内容 做个小实验 数据如何变成图表 1 2 维度和度量定义 3 度量映射图形&#xff0c;维度负责区分 1 可映射的数据类型 2 可视化字典 3 使用Tableau将数据变成图表(Tableau可视化原理) 1 2 拖拽 3 具体操作 4 总结 内容 点击左下角的工作表 tableau可以自动…

【WRF数据准备】气象驱动数据-ERA5是否需要单层位势数据?

目录 气象驱动数据-ERA5是否需要单层位势(Geopotential)数据?位势(Geopotential)输入的重要性Vtable的管理参考气象驱动数据-ERA5是否需要单层位势(Geopotential)数据? 本博客参考WRF论坛中讨论内容-How to use ERA5 Data From Copernicus Database,总结位势(Geopot…

用ResNet50+Qwen2-VL-2B-Instruct+LoRA模仿Diffusion-VLA的论文思路,在3090显卡上训练和测试成功

想一步步的实现Diffusion VLA论文的思路&#xff0c;不过论文的图像的输入用DINOv2进行特征提取的&#xff0c;我先把这个部分换成ResNet50。 老铁们&#xff0c;直接上代码&#xff1a; from PIL import Image import torch import torchvision.models as models from torch…