Swift Concurrency 学习

1. 概述

Swift Concurrency是Swift 5.5引入的现代并发编程模型,旨在简化异步编程并提高代码安全性。它提供了一套完整的工具来处理并发操作,包括async/await、Task、Actor等核心概念。

2. 核心概念

2.1 async/await

基本语法

// 异步函数定义
func fetchData() async -> String {
    // 模拟网络请求
    try? await Task.sleep(nanoseconds: 1_000_000_000)
    return "数据获取完成"
}

// 调用异步函数
func example() async {
    let result = await fetchData()
    print(result)
}

错误处理

func fetchDataWithError() async throws -> String {
    // 可能抛出错误的异步操作
    if Bool.random() {
        throw NetworkError.connectionFailed
    }
    return "成功获取数据"
}

func handleAsyncError() async {
    do {
        let data = try await fetchDataWithError()
        print(data)
    } catch {
        print("错误:\(error)")
    }
}

2.2 Task(任务)

创建和管理Task

// 创建无结构化任务
Task {
    let result = await fetchData()
    print("任务完成:\(result)")
}

// 带返回值的Task
let task = Task {
    return await fetchData()
}
let result = await task.value

// 取消任务
task.cancel()

Task优先级

Task(priority: .high) {
    await highPriorityWork()
}

Task(priority: .background) {
    await backgroundWork()
}

检查取消状态

func longRunningTask() async {
    for i in 1...1000 {
        // 检查任务是否被取消
        if Task.isCancelled {
            print("任务被取消")
            return
        }
        
        // 或者使用checkCancellation抛出异常
        try? Task.checkCancellation()
        
        await processItem(i)
    }
}

2.3 TaskGroup(任务组)

并发执行多个任务

func fetchMultipleData() async -> [String] {
    await withTaskGroup(of: String.self) { group in
        var results: [String] = []
        
        // 添加多个并发任务
        for i in 1...5 {
            group.addTask {
                return await fetchData(id: i)
            }
        }
        
        // 收集结果
        for await result in group {
            results.append(result)
        }
        
        return results
    }
}

ThrowingTaskGroup(可抛出异常的任务组)

func fetchMultipleDataWithErrors() async throws -> [String] {
    try await withThrowingTaskGroup(of: String.self) { group in
        var results: [String] = []
        
        for i in 1...5 {
            group.addTask {
                return try await fetchDataWithError(id: i)
            }
        }
        
        for try await result in group {
            results.append(result)
        }
        
        return results
    }
}

2.4 Actor

基本Actor定义

actor BankAccount {
    private var balance: Double = 0
    
    func deposit(amount: Double) {
        balance += amount
    }
    
    func withdraw(amount: Double) -> Bool {
        if balance >= amount {
            balance -= amount
            return true
        }
        return false
    }
    
    func getBalance() -> Double {
        return balance
    }
}

使用Actor

func bankingExample() async {
    let account = BankAccount()
    
    // 所有对actor的调用都是异步的
    await account.deposit(amount: 100)
    let success = await account.withdraw(amount: 50)
    let balance = await account.getBalance()
    
    print("余额:\(balance)")
}

nonisolated方法

actor DataManager {
    private var data: [String] = []
    
    func addData(_ item: String) {
        data.append(item)
    }
    
    // nonisolated方法可以同步调用
    nonisolated func getDataCount() -> Int {
        // 注意:不能访问actor的可变状态
        return 0 // 这里只能返回常量或计算值
    }
}

2.5 MainActor

UI更新和主线程操作

@MainActor
class ViewModel: ObservableObject {
    @Published var data: String = ""
    
    func updateData() async {
        // 在后台执行
        let newData = await fetchDataFromNetwork()
        
        // 自动在主线程执行UI更新
        self.data = newData
    }
}

MainActor.run

func updateUI() async {
    let data = await fetchData()
    
    // 确保UI更新在主线程执行
    await MainActor.run {
        // UI更新代码
        self.label.text = data
    }
}

3. 高级特性

3.1 AsyncSequence

自定义AsyncSequence

struct NumberSequence: AsyncSequence {
    typealias Element = Int
    
    let range: Range<Int>
    
    func makeAsyncIterator() -> AsyncIterator {
        return AsyncIterator(range: range)
    }
    
    struct AsyncIterator: AsyncIteratorProtocol {
        var current: Int
        let end: Int
        
        init(range: Range<Int>) {
            self.current = range.lowerBound
            self.end = range.upperBound
        }
        
        mutating func next() async -> Int? {
            guard current < end else { return nil }
            
            let value = current
            current += 1
            
            // 模拟异步操作
            try? await Task.sleep(nanoseconds: 100_000_000)
            return value
        }
    }
}

使用AsyncSequence

func useAsyncSequence() async {
    let sequence = NumberSequence(range: 1..<5)
    
    for await number in sequence {
        print("数字:\(number)")
    }
}

3.2 AsyncStream

创建简单的AsyncStream

func createNumberStream() -> AsyncStream<Int> {
    AsyncStream { continuation in
        Task {
            for i in 1...10 {
                continuation.yield(i)
                try? await Task.sleep(nanoseconds: 500_000_000)
            }
            continuation.finish()
        }
    }
}

func consumeStream() async {
    for await number in createNumberStream() {
        print("接收到:\(number)")
    }
}

4. 实际应用示例

4.1 网络请求管理器

actor NetworkManager {
    private var cache: [String: Data] = [:]
    
    func fetchData(from url: String) async throws -> Data {
        // 检查缓存
        if let cachedData = cache[url] {
            return cachedData
        }
        
        // 执行网络请求
        guard let url = URL(string: url) else {
            throw NetworkError.invalidURL
        }
        
        let (data, _) = try await URLSession.shared.data(from: url)
        
        // 缓存结果
        cache[url.absoluteString] = data
        
        return data
    }
    
    func clearCache() {
        cache.removeAll()
    }
}

4.2 并发下载管理器

class DownloadManager {
    private let networkManager = NetworkManager()
    
    func downloadFiles(urls: [String]) async -> [Result<Data, Error>] {
        await withTaskGroup(of: Result<Data, Error>.self) { group in
            var results: [Result<Data, Error>] = []
            
            for url in urls {
                group.addTask { [weak self] in
                    do {
                        let data = try await self?.networkManager.fetchData(from: url) ?? Data()
                        return .success(data)
                    } catch {
                        return .failure(error)
                    }
                }
            }
            
            for await result in group {
                results.append(result)
            }
            
            return results
        }
    }
}

4.3 定时器实现

actor Timer {
    private var isRunning = false
    
    func start(interval: TimeInterval, action: @escaping () async -> Void) {
        guard !isRunning else { return }
        isRunning = true
        
        Task { [weak self] in
            while await self?.isRunning == true {
                await action()
                try? await Task.sleep(nanoseconds: UInt64(interval * 1_000_000_000))
            }
        }
    }
    
    func stop() {
        isRunning = false
    }
}

5. 最佳实践

5.1 避免阻塞主线程

// ❌ 错误做法 - 阻塞主线程
@MainActor
func badExample() {
    let result = fetchData() // 这会阻塞UI
}

// ✅ 正确做法 - 使用async/await
@MainActor
func goodExample() async {
    let result = await fetchData() // 不阻塞UI
}

5.2 合理使用Actor

// ✅ 适合使用Actor的场景:共享可变状态
actor Counter {
    private var value = 0
    
    func increment() -> Int {
        value += 1
        return value
    }
}

// ❌ 不适合使用Actor的场景:无状态操作
actor MathUtils { // 这个不应该是actor
    func add(_ a: Int, _ b: Int) -> Int {
        return a + b
    }
}

5.3 错误处理策略

func robustNetworkCall() async -> String {
    let maxRetries = 3
    
    for attempt in 1...maxRetries {
        do {
            return try await fetchDataWithError()
        } catch {
            if attempt == maxRetries {
                return "获取失败:\(error)"
            }
            // 重试前等待
            try? await Task.sleep(nanoseconds: UInt64(attempt * 1_000_000_000))
        }
    }
    
    return "未知错误"
}

6. 性能考虑

6.1 避免过度创建Task

// ❌ 避免在循环中创建大量Task
func inefficient() async {
    for i in 1...1000 {
        Task {
            await processItem(i)
        }
    }
}

// ✅ 使用TaskGroup批量处理
func efficient() async {
    await withTaskGroup(of: Void.self) { group in
        for i in 1...1000 {
            group.addTask {
                await processItem(i)
            }
        }
    }
}

6.2 合理设置Task优先级

func prioritizeWork() {
    // 用户交互相关的高优先级任务
    Task(priority: .userInitiated) {
        await updateUI()
    }
    
    // 后台数据同步低优先级任务
    Task(priority: .background) {
        await syncDataToServer()
    }
}

7. 迁移指南

7.1 从GCD迁移

// 旧的GCD方式
DispatchQueue.global().async {
    let result = performWork()
    DispatchQueue.main.async {
        updateUI(with: result)
    }
}

// 新的Swift Concurrency方式
Task {
    let result = await performWork()
    await MainActor.run {
        updateUI(with: result)
    }
}

7.2 从Combine迁移

// 旧的Combine方式
func fetchUserData() -> AnyPublisher<User, Error> {
    URLSession.shared.dataTaskPublisher(for: url)
        .map(\.data)
        .decode(type: User.self, decoder: JSONDecoder())
        .eraseToAnyPublisher()
}

// 新的async/await方式
func fetchUserData() async throws -> User {
    let (data, _) = try await URLSession.shared.data(from: url)
    return try JSONDecoder().decode(User.self, from: data)
}

总结

Swift Concurrency提供了一个强大而安全的并发编程模型,主要优势包括:

  • 类型安全:编译时检查并发安全性
  • 简洁语法:async/await让异步代码更易读
  • 数据竞争防护:Actor模型防止数据竞争
  • 结构化并发:TaskGroup提供清晰的任务管理
  • 性能优化:协作式多任务处理

通过合理使用这些特性,可以编写出更安全、更高效的并发代码。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容