Concurrency学习(整理中……)

102 阅读3分钟

1. 系统要求

iOS 13.0 +

2. 学习路径

1.官方教程-Concurrency

和非Concurrency的异步编程不同,Swift中的asynchronous函数坑可能脱离它正在运行的线程,当第一个函数被阻塞时,另一个asynchronous函数可以在该线程上运行,asynchronous恢复时,执行线程可能不一样

定义和调用异步函数

  • 定义一步函数
func listPhotos(inGallery name: String) async -> [String] {
    let result = // ... some asynchronous networking code ...
    return result
}
  • 调用
let photoNames = await listPhotos(inGallery: "Summer Vacation")
let sortedNames = photoNames.sorted()
let name = sortedNames[0]
let photo = await downloadPhoto(named: name)
show(photo)

使用Task.sleep(until:tolerance:clock:) 模拟异步操作,便于理解函数执行

异步序列:Asynchronous Sequences

  • For-await-in循环
import Foundation
let handle = FileHandle.standardInput
for try await line in handle.bytes.lines {
    print(line)
}

并发执行asynchronous函数

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)

Tasks和Task Groups

Task特性:有层级(结构化并发:structured concurrency)、调度优先级/取消

let group = await withTaskGroup(of: Data.self) { taskGroup in
    let photoNames = await listPhotos(inGallery: "Summer Vacation")
    for name in photoNames {
        taskGroup.addTask { await downloadPhoto(named: name) }
    }
}
  • Task Group

不要在create创建之外的地方使用,因为add a child task是一个》 mutating(可变)操作, 否则不能保障上下文一致

Group内的task是并行执行的,执行顺序不固定

Group取消操作:1. cancelAll() 2. task被取消

使用addTaskUnlessCancelled(priority:body:)addTask(priority:body:) 的区别

Task Group的API TaskGroup

非结构化的并发

Task

创建 Task.init(priority:operation:)Task.detached(priority:operation:) (非current actor)

let newPhoto = // ... some photo data ...
let handle = Task {
    return await add(newPhoto, toGalleryNamed: "Spring Adventures")
}
let result = await handle.value

Actors

  • 引用类型
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
    }
}

extension TemperatureLogger {
    // 已经在actor内运行,所以不需要使用await
    func update(with measurement: Int) {
        measurements.append(measurement)
        if measurement > max {
            max = measurement
        }
    }
}

let logger = TemperatureLogger(label: "Outdoors", measurement: 25)
print(await logger.max)
  • 参与者隔离 actor isolation.

Sendable Types

A type that can be shared from one concurrency domain to another is known as a sendable type. For example, it can be passed as an argument when calling an actor method or be returned as the result of a task

Sendable Type:可以从一个并发域传递给另一个的类型。如:在Actor方法中,参数传递、作为返回值

struct TemperatureReading: Sendable {
    var measurement: Int
}

// 和上边的定义等效
//struct TemperatureReading {
//    var measurement: Int
//}

extension TemperatureLogger {
    func addReading(from reading: TemperatureReading) {
        measurements.append(reading.measurement)
    }
}


let logger = TemperatureLogger(label: "Tea kettle", measurement: 85)
let reading = TemperatureReading(measurement: 45)
await logger.addReading(from: reading)

2.Concurrency优势和迁移

Meet async/await in Swift

3.实现原理

Explore structured concurrency in Swift

4.示例代码

Swift Concurrency by Example

5.使用Actor防止数据竞争

Protect mutable state with Swift actors

6.SwiftUI中的应用

Discover concurrency in SwiftUI

7.URL Session中使用

Use async/await with URLSession

8.Swift Concurrency 背后的故事

播客的访谈

3.Concurrency和Combine

由于 Swift Concurrency 的推出和大量的 Session 发布,特别是 AsyncSequence 的出现,以及正在路上的 AsyncStream、AsyncThrowingStreamcontinuation 提案(在Xcode 13.0 beta 3 AsyncStream 正式 release ),这些越来越多和 Combine 功能重叠的特性出现在 Swift Concurrency 蓝图里时,大家开始猜测是否 Combine 会被 Swift Concurrency 替代。关于未来是 Swift Concurrency 还是 Combine,我的感觉是,Combine 更侧重在响应式编程上,而响应式编程并不是所有开发人员都会接受的,而 Swift Concurrency 是所有人都愿意接受的开发方式,从 Swift Concurrency 推出后开发者使用的数量和社区反应火热程度来看都比 Combine 要大。在苹果对 Combine 有下一步动作之前,我还是更偏向 Swift Concurrency。 ——《戴铭的开发小册子》