Async/Await 是一对用于以同步风格编写异步代码的关键字,Swift 自 iOS 13 起可用,Kotlin 通过协程支持。根据 Apple Swift Documentation, 2026,Async/Await 取代了 callback 链和 GCD,使异步代码变得线性且可读。关键字 async 将函数标记为异步,await 则暂停函数的执行,直到获得结果。
核心要点
Async/Await 是一种语言构造,可以像编写同步代码一样线性地编写异步代码。在 Swift 中,它随 iOS 13 / macOS 10.15 及 Swift Concurrency 框架一同出现。在 Kotlin 中,async/await 从 1.3 版本起可通过协程库(kotlinx.coroutines)使用。
在 async/await 出现之前,异步代码基于 callback、GCD 或 RxSwift 构建。嵌套的 callback 链导致 callback hell——深层嵌套使阅读和调试变得困难。Async/Await 通过允许异步函数在 await 点“暂停”并在获得结果后恢复,解决了这个问题。
根据 Google(2025)的数据,在 Kotlin 中使用 async/await 可将异步代码行数比 callback 方式减少 40–60%。在 Swift 中,Swift Concurrency 在 2025 年已发布应用中的采用率达到 68%。iOS 16 在 UIKit、SwiftUI 和 Foundation 中添加了对 Swift Concurrency 的支持,使 async/await 成为所有 Apple 新项目的标准工具。
async/await 与线程的关键区别是无阻塞暂停。当函数遇到 await 时,它会暂停并释放当前线程供其他任务使用。异步操作完成后,函数在同一或另一线程上恢复。这称为协作式多任务处理。
Async 函数被编译为 state machine——一种管理执行状态的状态机。在 await 点,编译器保存上下文(局部变量、返回地址)并将控制权交给运行时。当结果就绪时,运行时恢复上下文并继续执行。
在 Swift 中,该状态机在编译器 SIL(Swift Intermediate Language)层面实现。在 Kotlin 中——通过 Continuation Passing Style(CPS)机制:每个 suspend 函数接受隐藏参数 Continuation,通过它返回结果。两种方法都保证安全恢复且不会内存泄漏。
Callback 方式需要传递闭包,在操作完成后调用。对于三个连续请求,会产生三层嵌套,每层都有错误处理。Async/Await 将同样的三个请求变成三行连续代码和一个统一 catch 块。
GCD(DispatchQueue)通过 serial 队列和 DispatchGroup 解决 callback hell 问题,但仍显冗长。对于简单任务——加载 user,然后 friends,然后 UI——需要创建队列、组和 notify 块。Async/Await 在单个函数中用三行代码完成同样任务。
| 方面 | Callback | GCD | Async/Await |
|---|---|---|---|
| 嵌套 | 深层(pyramid of doom) | 中等(组+notify) | 线性(flat) |
| 错误处理 | 每个 callback | 手动 | 统一(try/catch) |
| 取消 | 手动 | 有限 | Task.cancel() |
| 线程安全 | 手动 | 通过 serial queue | 通过 MainActor |
根据 Apple WWDC 2024 的数据,Swift Concurrency async/await 是新代码的推荐方式。GCD 仍用于与 C 库集成以及特定的底层线程处理场景。
Task 是 Swift 中异步工作的基本单元。Task 在现有 actor 的上下文中或在任意线程上创建。在 Task 内部可以通过 await 调用 async 函数。TaskGroup 允许并行启动多个子任务并收集结果——相当于强化版 DispatchGroup。
Actor 是线程安全的引用类型,保护其状态免受数据竞争。编译器保证只能通过 async 调用或 actor isolation 内访问 actor 的属性。Actor 取代 serial DispatchQueue 来保护共享可变状态,无需手动锁。
Structured Concurrency 原则是:每个异步任务都有父任务,父任务在所有子任务完成前不会结束。如果任务 A 启动 Task { await B() },那么 A 等待 B。这防止任务泄漏并保证可预测的生命周期。
在 Kotlin 中,async/await 通过 coroutines(协程)实现——语言的轻量线程。函数用 suspend 关键字标记(相当于 Swift 的 async)。启动时使用 launch(fire-and-forget)或 async(带结果)。await 用于获取 async 的结果。
Dispatcher 决定协程在哪个线程池上执行:Dispatchers.Main 用于 UI,Dispatchers.IO 用于网络/磁盘,Dispatchers.Default 用于 CPU 密集型任务。Structured Concurrency 通过 CoroutineScope 保证——取消 scope 时所有子协程都会被取消。
根据 JetBrains(2025)的数据,Google Play 中 97% 的 Android 应用使用 kotlinx.coroutines,其中 82% 使用 async/await 进行网络请求。协程已成为 Android 异步编程的事实标准。Kotlin Multiplatform 也支持协程,允许在 Android、iOS 和服务器端使用统一的异步代码。
我们为每种语言看两个示例:顺序加载数据和用 TaskGroup 或 async/await 的并行请求。
await 暂停执行直到获得用户数据,然后——直到获得好友。没有嵌套闭包。
func loadProfile() async throws -> Profile {
let user = try await api.fetchUser()
let friends = try await api.fetchFriends(for: user.id)
return Profile(user: user, friends: friends)
}
TaskGroup 并行启动任务并将结果收集到数组中。结果顺序可能与启动顺序不一致。
func loadParallel() async throws -> [String] {
await withThrowingTaskGroup(of: String.self) { group in
group.addTask { try await api.fetchName() }
group.addTask { try await api.fetchEmail() }
group.addTask { try await api.fetchAvatar() }
var results = [String]()
for try await value in group { results.append(value) }
return results
}
}
suspend 函数可以调用其他 suspend 函数。类似于 Swift:顺序调用。
suspend fun loadProfile(): Profile {
val user = api.fetchUser()
val friends = api.fetchFriends(user.id)
return Profile(user, friends)
}
在 Kotlin 中,并行通过 coroutineScope 搭配每个请求的 async 实现。
suspend fun loadParallel(): List<String> = coroutineScope {
val name = async { api.fetchName() }
val email = async { api.fetchEmail() }
val avatar = async { api.fetchAvatar() }
listOf(name.await(), email.await(), avatar.await())
}
忘记 Task { }——无法在没有 Task 包装的情况下从同步上下文调用异步函数。在 Swift 中这会产生编译错误。在 Kotlin 中需要通过 lifecycleScope 或 viewModelScope 启动。从普通函数调用 suspend 函数无法编译。
并非每个函数都需要变成异步。CPU 密集型且无 I/O 的任务不会从 async 中受益——最好在带 .userInitiated QoS 的 DispatchQueue 上执行。Async/Await 针对 I/O-bound 操作优化:网络、磁盘、等待。
在主线程上使用 .result(同步等待 async 函数结果)会导致阻塞。在 Swift 中,Apple 不建议使用 Task.synchronousWait。在 Kotlin 中,主线程上的 runBlocking 是反模式,请使用 lifecycleScope。
如果 Task 没有保存到类的属性中,在离开上下文后它会被取消。在 Swift 中 Task 是 scoped——其生命周期与创建它的上下文绑定。对于长时间运行的操作,请将 Task 保存到属性中。
常见问题
Async/Await 是一种语言构造,无需创建队列。DispatchQueue 是管理线程的系统 API。async/await 在语言层面编译为 state machine,GCD 在操作系统层面编译为 syscall。
不会——await 暂停函数,但会释放线程供其他任务使用。操作完成后,函数在池中任意可用线程上恢复。
可以——在 Swift 中通过 Task.cancel(),在 Kotlin 中通过 Job.cancel()。根据 Structured Concurrency,取消会传播到所有子任务。代码通过 Task.isCancelled 或 ensureActive() 自行检查取消标志。
MainActor 是其属性和方法始终在主线程上执行的 actor。将函数标记为 @MainActor,即可保证 UI 更新在正确的线程上进行,取代 DispatchQueue.main.async。
Async/Await 可用于 Swift(iOS 13+)、Kotlin(通过 kotlinx.coroutines)、Dart(Flutter)、JavaScript/TypeScript、Python、C#、Rust 和 Go(通过带语法糖的 goroutines)。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。