2-4.【Concurrency】Continuation 是什么?与 async/await 有何关系?

17 阅读3分钟

在 Swift(乃至整个并发世界)里:

如果你真正理解了 continuation,你就理解了 async/await 的底层本质。

我会按 概念 → Swift 里的具体形态 → 与 async/await 的关系 → 常见误区 来讲。


一句话定义(先刻在脑子里)

Continuation =「从当前点开始,程序接下来该怎么继续执行」的一个可保存、可传递、可稍后调用的对象。

换句话说:

continuation 就是 “未来的自己”


1️⃣ 直观理解(不用术语)

看这段代码:

let x = await foo()
print(x)

await foo() 这一行:

  • 当前函数不能继续往下跑
  • 但“等 foo 完成之后该干什么”是完全确定的

这段“之后该干什么”的逻辑:

print(x)

👉 这就是一个 continuation


2️⃣ continuation 在 Swift 中到底是什么?

在 Swift Concurrency 里,continuation 不是抽象概念,而是真实存在的东西

在编译器 / runtime 层面

continuation 由以下几部分组成:

  1. resume function

    • 一个函数指针
    • 指向“await 之后的代码块”
  2. async context

    • 保存局部变量、状态机状态
  3. executor 信息

    • 决定在哪里恢复执行

合在一起:

continuation = (async context + resume entry + executor)


3️⃣ async/await 和 continuation 的关系(核心)

❓ async/await 做了什么?

async/await 的本质就是:
把 continuation 自动、隐式地帮你创建和管理了。


不用 async/await(手写 continuation)

func foo(_ cont: @escaping (Int) -> Void) {
    bar { result in
        cont(result + 1)
    }
}

你在手动传递 continuation


用 async/await

func foo() async -> Int {
    let x = await bar()
    return x + 1
}

编译器在背后自动做了:

  • 创建 continuation
  • 保存当前上下文
  • 把 continuation 传给 bar
  • 在合适的 executor 上 resume

👉 你写的是顺序代码,底层仍然是 continuation。


4️⃣ withUnsafeContinuation 是什么角色?

这是 Swift 暴露给用户的 continuation API

func legacy() async -> Int {
    await withCheckedContinuation { cont in
        legacyAPI { value in
            cont.resume(returning: value)
        }
    }
}

这里:

  • cont 就是当前 async 函数的 continuation

  • 调用 resume

    • 就等于“触发 await 后面的代码继续执行”

⚠️ 注意:

  • resume 只能调用一次
  • 否则 continuation 会崩(checked 版会直接 trap)

5️⃣ continuation 与“状态机”的关系

continuation ≠ 状态机
continuation = 状态机的一个“入口点”

  • 状态机:

    • 决定你现在在哪个状态
  • continuation:

    • 是“从这个状态继续跑”的 callable handle

你可以把它理解为:

state machine + continuation = coroutine

6️⃣ continuation 与线程的关系(常见误解)

❌ 错误理解

continuation = 保存当前线程

✅ 正确理解

continuation 不保存线程,只保存“逻辑上的下一步”。

  • 恢复时:

    • 可能在同一个线程
    • 也可能在完全不同的线程
  • 线程由 executor 决定


7️⃣ continuation 在错误、取消中的作用

错误传播

await foo() // throws
  • continuation 包含:

    • normal resume
    • error resume

cancellation

  • task 被取消时

  • runtime 会:

    • 找到 continuation
    • 恢复执行
    • 抛出 CancellationError

8️⃣ 和其他语言的对比(帮助定位)

语言continuation 表现
Swift隐式 + 显式(withContinuation)
KotlinContinuation<T> 参数
JSPromise.then
C++20coroutine_handle
Schemecall/cc

Swift 的设计目标是:

让 99% 的 continuation 消失在语法糖后面


9️⃣ 终极记忆版总结

Continuation 是“await 之后要做什么”的可执行表示。
async/await 的全部魔法,就是把 continuation 自动保存、传递、恢复。