Async/Await:核心概念、async 函数与 await 的使用

作者: IT Sectr 发布日期: 2026-03-16 阅读时间: 8 分钟

Async/Await 是一对用于以同步风格编写异步代码的关键字,Swift 自 iOS 13 起可用,Kotlin 通过协程支持。根据 Apple Swift Documentation, 2026Async/Await 取代了 callback 链和 GCD,使异步代码变得线性且可读。关键字 async 将函数标记为异步,await 则暂停函数的执行,直到获得结果。

核心要点

  • Async/Await — 用于异步代码的语法糖,无需嵌套 callback
  • async 将函数标记为异步且可暂停
  • await 暂停函数执行,直到异步操作完成
  • Task 在 Swift 中创建带有上下文的新异步工作单元
  • Structured Concurrency 保证所有子任务在父任务完成前结束

什么是 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/Await 如何工作:暂停与恢复

Async 函数被编译为 state machine——一种管理执行状态的状态机。在 await 点,编译器保存上下文(局部变量、返回地址)并将控制权交给运行时。当结果就绪时,运行时恢复上下文并继续执行。

Swift 中,该状态机在编译器 SIL(Swift Intermediate Language)层面实现。在 Kotlin 中——通过 Continuation Passing Style(CPS)机制:每个 suspend 函数接受隐藏参数 Continuation,通过它返回结果。两种方法都保证安全恢复且不会内存泄漏。

  • Swift — 编译器将 async 函数转换为带 runAsync coroutine frame 的 SIL
  • Kotlin — 每个 suspend 函数获得 Continuation 并将执行委托给调度器
  • 两种语言 — 在 await 时释放线程,等待期间不阻塞
  • 异常 — 通过标准机制(throws / try-catch)抛出

Async/Await 与 Callbacks 和 GCD:方法对比

Callback 方式需要传递闭包,在操作完成后调用。对于三个连续请求,会产生三层嵌套,每层都有错误处理。Async/Await 将同样的三个请求变成三行连续代码和一个统一 catch 块。

GCD(DispatchQueue)通过 serial 队列和 DispatchGroup 解决 callback hell 问题,但仍显冗长。对于简单任务——加载 user,然后 friends,然后 UI——需要创建队列、组和 notify 块。Async/Await 在单个函数中用三行代码完成同样任务。

方面CallbackGCDAsync/Await
嵌套深层(pyramid of doom)中等(组+notify)线性(flat)
错误处理每个 callback手动统一(try/catch)
取消手动有限Task.cancel()
线程安全手动通过 serial queue通过 MainActor

根据 Apple WWDC 2024 的数据,Swift Concurrency async/await 是新代码的推荐方式。GCD 仍用于与 C 库集成以及特定的底层线程处理场景。

Swift Concurrency:Task、TaskGroup 和 Actor

Task 是 Swift 中异步工作的基本单元。Task 在现有 actor 的上下文中或在任意线程上创建。在 Task 内部可以通过 await 调用 async 函数。TaskGroup 允许并行启动多个子任务并收集结果——相当于强化版 DispatchGroup。

Actor 是线程安全的引用类型,保护其状态免受数据竞争。编译器保证只能通过 async 调用或 actor isolation 内访问 actor 的属性。Actor 取代 serial DispatchQueue 来保护共享可变状态,无需手动锁。

Structured Concurrency

Structured Concurrency 原则是:每个异步任务都有父任务,父任务在所有子任务完成前不会结束。如果任务 A 启动 Task { await B() },那么 A 等待 B。这防止任务泄漏并保证可预测的生命周期。

Kotlin 中带协程的 Async/Await

在 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 和服务器端使用统一的异步代码。

Swift 和 Kotlin 中 Async/Await 的代码示例

我们为每种语言看两个示例:顺序加载数据和用 TaskGroupasync/await 的并行请求。

Swift:顺序 async 调用

await 暂停执行直到获得用户数据,然后——直到获得好友。没有嵌套闭包。

swift
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)
}

Swift:使用 TaskGroup 的并行请求

TaskGroup 并行启动任务并将结果收集到数组中。结果顺序可能与启动顺序不一致。

swift
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
    }
}

Kotlin:使用 async/await 的顺序调用

suspend 函数可以调用其他 suspend 函数。类似于 Swift:顺序调用。

kotlin
suspend fun loadProfile(): Profile {
    val user = api.fetchUser()
    val friends = api.fetchFriends(user.id)
    return Profile(user, friends)
}

Kotlin:使用 async/await 的并行请求

在 Kotlin 中,并行通过 coroutineScope 搭配每个请求的 async 实现。

kotlin
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())
}

Async/Await 的典型错误与限制

忘记 Task { }——无法在没有 Task 包装的情况下从同步上下文调用异步函数。在 Swift 中这会产生编译错误。在 Kotlin 中需要通过 lifecycleScopeviewModelScope 启动。从普通函数调用 suspend 函数无法编译。

无必要地过度使用 async

并非每个函数都需要变成异步。CPU 密集型且无 I/O 的任务不会从 async 中受益——最好在带 .userInitiated QoS 的 DispatchQueue 上执行。Async/Await 针对 I/O-bound 操作优化:网络、磁盘、等待。

通过 .result 阻塞主线程

在主线程上使用 .result(同步等待 async 函数结果)会导致阻塞。在 Swift 中,Apple 不建议使用 Task.synchronousWait。在 Kotlin 中,主线程上的 runBlocking 是反模式,请使用 lifecycleScope。

取消时 Task 泄漏

如果 Task 没有保存到类的属性中,在离开上下文后它会被取消。在 Swift 中 Task 是 scoped——其生命周期与创建它的上下文绑定。对于长时间运行的操作,请将 Task 保存到属性中。

常见问题

async/await 与 DispatchQueue 有何区别?

Async/Await 是一种语言构造,无需创建队列。DispatchQueue 是管理线程的系统 API。async/await 在语言层面编译为 state machine,GCD 在操作系统层面编译为 syscall。

await 会阻塞线程吗?

不会——await 暂停函数,但会释放线程供其他任务使用。操作完成后,函数在池中任意可用线程上恢复。

可以取消 async 任务吗?

可以——在 Swift 中通过 Task.cancel(),在 Kotlin 中通过 Job.cancel()。根据 Structured Concurrency,取消会传播到所有子任务。代码通过 Task.isCancelledensureActive() 自行检查取消标志。

Swift 中的 MainActor 是什么?

MainActor 是其属性和方法始终在主线程上执行的 actor。将函数标记为 @MainActor,即可保证 UI 更新在正确的线程上进行,取代 DispatchQueue.main.async。

哪些语言支持 async/await?

Async/Await 可用于 Swift(iOS 13+)、Kotlin(通过 kotlinx.coroutines)、Dart(Flutter)、JavaScript/TypeScriptPythonC#RustGo(通过带语法糖的 goroutines)。

总结

  • Async/Await — 用于线性异步代码的语言构造,无 callback hell
  • Swift Concurrency 提供 Task、TaskGroup、Actor 和 Structured Concurrency
  • Kotlin 协程使用 suspend 函数、Dispatchers 和协程作用域
  • 无阻塞暂停——async/await 与线程和队列的关键区别
  • Structured Concurrency 保证所有子任务在父任务之前完成
  • Async/Await 与 GCD——前者更适合新代码,后者用于 legacy 和底层
  • MainActor(Swift)和 Dispatchers.Main(Kotlin)保护 UI 线程免受后台操作影响

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读