Swift Concurrency:用最简单方式理解苹果官方的异步并发编程

10 阅读4分钟

Swift Concurrency:用最简单方式理解苹果官方的异步并发编程

Swift Concurrency 是苹果从 Swift 5.5 开始原生支持的一套异步和并发编程工具,目的是让异步代码写起来更简单、更安全、更高效。它用现代语法和机制,帮助开发者避免传统异步编程的复杂和错误,尤其适合处理网络请求、文件操作、复杂计算等耗时任务。

1. 什么是并发(Concurrency)?

并发指的是多个任务的执行时间有重叠,但不一定同时运行。Swift Concurrency 关注如何用结构化、安全的方式管理这些异步任务,避免混乱和错误。

2. Swift Concurrency 的核心概念和特性

2.1 async / await -- 异步函数和等待

  • async:标记函数是异步的,表示函数内部可能会暂停执行,等待耗时操作完成。
  • await:调用异步函数时使用,表示“等待”异步操作完成后再继续执行。

这样写异步代码就像写同步代码一样简单,避免了回调地狱。

func fetchData() async throws -> String {
    let url = URL(string: "https://api.example.com/data")!
    let (data, _) = try await URLSession.shared.data(from: url)
    return String(data: data, encoding: .utf8) ?? ""
}

Task {
    do {
        let result = try await fetchData()
        print("获取数据:(result)")
    } catch {
        print("请求失败:(error)")
    }
}

2.2 Task -- 异步任务的执行单元

  • Task 是执行异步代码的基本单位。
  • 支持创建、取消、设置优先级。
  • 任务之间可以形成父子关系,自动管理生命周期。
let task = Task {
    await someAsyncFunction()
}
// 取消任务
task.cancel()

2.3 结构化并发 -- 任务的管理和组织

  • 任务形成树状结构,父任务会等待所有子任务完成。
  • 自动处理任务取消和错误传播,避免任务孤儿和资源泄漏。
func loadMultipleData() async {
    await withTaskGroup(of: String.self) { group in
        group.addTask { await fetchDataFromServer1() }
        group.addTask { await fetchDataFromServer2() }

        for await result in group {
            print("收到数据:(result)")
        }
    }
}

2.4 Actor -- 保护共享数据安全

  • Actor 是一种特殊的类,保证同一时间只有一个任务访问它的内部状态。
  • 解决多线程环境下的数据竞争问题,比传统锁机制更安全且性能更好。
actor Counter {
    private var value = 0
    func increment() {
        value += 1
    }
    func getValue() -> Int {
        return value
    }
}

let counter = Counter()
Task {
    await counter.increment()
    let current = await counter.getValue()
    print("计数器当前值:(current)")
}

3. Swift Concurrency 解决了哪些问题?

  • 简化异步代码:用 async/await 替代回调,代码更直观。
  • 提高安全性:编译器帮你检查错误处理和取消逻辑,减少遗漏。
  • 结构化管理任务:自动管理任务生命周期,避免内存泄漏。
  • 避免数据竞争:用 Actor 保护共享状态,避免多线程冲突。
  • 提升性能和响应性:合理调度任务,避免主线程阻塞,充分利用多核 CPU。

4. 什么时候用 Swift Concurrency?

  • 需要执行网络请求、文件读写、数据库操作等耗时任务。
  • 保持界面流畅,避免主线程卡顿。
  • 管理多个异步任务,且任务间有依赖关系。
  • 需要安全访问和修改共享数据。
  • 希望代码简洁、易维护,替代传统 GCD、回调等方式。

5. 详细示例代码和说明

5.1 使用 async/await 进行网络请求

func downloadImage() async throws -> UIImage {
    let url = URL(string: "https://example.com/image.png")!
    let (data, _) = try await URLSession.shared.data(from: url)
    guard let image = UIImage(data: data) else {
        throw URLError(.badServerResponse)
    }
    return image
}

Task {
    do {
        let image = try await downloadImage()
        print("图片下载成功")
    } catch {
        print("下载失败:(error)")
    }
}

5.2 使用 TaskGroup 并发请求多个接口

func fetchUserIDs() async -> [Int] {
    await withTaskGroup(of: Int.self) { group in
        let servers = ["primary", "secondary", "backup"]
        for server in servers {
            group.addTask {
                return await fetchUserID(from: server)
            }
        }

        var results = [Int]()
        for await userID in group {
            results.append(userID)
        }
        return results
    }
}

func fetchUserID(from server: String) async -> Int {
    // 模拟网络请求延迟
    try? await Task.sleep(nanoseconds: 500_000_000)
    return Int.random(in: 1...100)
}

Task {
    let userIDs = await fetchUserIDs()
    print("用户ID列表:(userIDs)")
}

5.3 使用 Actor 保护共享状态

swift
actor BankAccount {
    private var balance: Double = 0.0

    func deposit(amount: Double) {
        balance += amount
    }

    func withdraw(amount: Double) -> Bool {
        if balance >= amount {
            balance -= amount
            return true
        } else {
            return false
        }
    }

    func getBalance() -> Double {
        return balance
    }
}

let account = BankAccount()
Task {
    await account.deposit(amount: 1000)
    let success = await account.withdraw(amount: 500)
    print("取款成功吗? (success)")
    print("余额:(await account.getBalance())")
}

6. Swift Concurrency 的性能和安全性优势

  • Swift 5.10 及以后版本,编译器能在编译阶段检测数据竞争,避免运行时错误。
  • 通过全局执行器和 Actor 串行执行器,保证任务调度合理,避免主线程阻塞。
  • Instruments 工具支持并发代码的可视化分析,帮助定位性能瓶颈和错误。
  • 任务只在需要时占用 Actor,避免长时间阻塞,提升并行效率。

7. 总结

Swift Concurrency 是苹果为 Swift 设计的现代异步编程方案,核心是 async/await、Task、结构化并发和 Actor。它让异步代码更简单、清晰、安全,避免了传统回调和锁的复杂性,提升了性能和用户体验。无论是网络请求、文件操作,还是复杂的多任务协作,Swift Concurrency 都是首选工具。

欢迎尝试以上示例,结合实际项目,体会 Swift Concurrency 带来的高效与安全。

OSZAR »