Swift学习笔记 并发(Concurrency)

发布时间 2024-01-07 08:09:53作者: zwvista

async await

async(异步)函数(方法)是 Swift 并发所引入的一种新的函数类型。
async 函数(方法)在定义时用 async 关键字来标记。
async 函数(方法)具有中断和恢复功能。中断点用 await 关键字来标记。
async 函数(方法)在中断并恢复前后所处的线程可能会有所不同。

允许调用异步函数或异步方法的场所

  1. 其他异步函数或异步方法
  2. main函数
  3. Task 中的代码
// 声明异步函数时使用 async
func listPhotos(inGallery name: String) async -> [String] {
    let result = // ... some asynchronous networking code ...
    return result
}
// 调用异步函数时使用 await
// 调用 Task.yield 方法可以提交控制权
func generateSlideshow(forGallery gallery: String) async {
    let photos = await listPhotos(inGallery: gallery)
    for photo in photos {
        // ... render a few seconds of video for this photo ...
        await Task.yield()
    }
}
// 声明会抛异常的异步函数时使用 async 和 throws
// 调用会抛异常的异步函数时使用 try 和 await
// 调用 Task.sleep 方法可以让异步函数中断执行一定时间
func listPhotos(inGallery name: String) async throws -> [String] {
    try await Task.sleep(for: .seconds(2))
    return ["IMG001", "IMG99", "IMG0404"]
}

let async

// 同步执行,依次下载三张图片
let firstPhoto = await downloadPhoto(named: photoNames[0])
let secondPhoto = await downloadPhoto(named: photoNames[1])
let thirdPhoto = await downloadPhoto(named: photoNames[2])
let photos = [firstPhoto, secondPhoto, thirdPhoto]
show(photos)
// 异步执行,同时下载三张图片
async let firstPhoto = downloadPhoto(named: photoNames[0])
async let secondPhoto = downloadPhoto(named: photoNames[1])
async let thirdPhoto = downloadPhoto(named: photoNames[2])
let photos = await [firstPhoto, secondPhoto, thirdPhoto]
show(photos)

Task

TaskGroup

actor

actor 是 Swift 并发所引入的一种新的数据类型。
可以把 actor 看成线程安全的 class,即 actor 也是一种引用类型。
但 actor 的数据以及方法缺省具有 async 特性,在读取 actor 的数据以及调用 actor 方法时需要用 await 来标记。
不能在 actor 之外更新 actor 的数据

// actor 本质上是一种线程安全的 class 
actor TemperatureLogger {
    let label: String
    var measurements: [Int]
    private(set) var max: Int

    init(label: String, measurement: Int) {
        self.label = label
        self.measurements = [measurement]
        self.max = measurement
    }
}
// 在 actor 之外读取 actor 的数据时需要 await
let logger = TemperatureLogger(label: "Outdoors", measurement: 25)
print(await logger.max)
// Prints "25"

GlobalActor

MainActor

需要在 main 线程中运行的代码(比如 UI 的更新)可以使用 MainActor 标记

// 使用 MainActor 标记需要在 main 线程中使用的 ViewModel 类
@MainActor
final class HomeViewModel {
    // ..
}
// 使用 MainActor 标记 ViewModel 类中需要在 main 线程中使用的数据成员
final class HomeViewModel {
    @MainActor var images: [UIImage] = []
}
// 直接调用 MainActor.run 方法在 main 线程中执行更新 UI 的代码
Task {
    await someHeavyBackgroundOperation()
    await MainActor.run {
        // Perform UI updates
    }
}

MainActor usage in Swift explained to dispatch to the main thread