/* Page prose (zh-Hans) */
"ClassicVsModernWrappingUp" = "# 小结\n\n你现在已经看过一个日常任务（获取两样东西，把它们合并，处理错误，在主线程上交付）用两种方式被解决，而现代版本在可读性、安全性和纯粹的代码行数上都胜出。不过，诚实的结论并不是“重写一切”；而是知道什么映射到什么，以及在哪里迁移真的划算。下面的总结是对这两者的一张地图。\n\n* 现代模型在同一个任务上胜出：没有共享的可变状态，没有 `enter`/`leave`，一条错误路径，还有通过 `@MainActor` 实现的自动主线程跳转。\n* 每一个经典工具都有一个现代对应物：\n  * completion handler ➡️ `async` 函数\n  * `DispatchGroup`/信号量 ➡️ `async let`/`TaskGroup`\n  * 串行队列守护 ➡️ **actor**\n  * `DispatchQueue.main` ➡️ **`@MainActor`**\n  * 手动的 `Operation` 取消 ➡️ 协作式的 `Task` 取消\n  * delegate/回调 ➡️ `AsyncStream`/continuation\n* **经典仍然有它的一席之地**，用于更老的 API、精细的 dispatch 控制、早于 `async`/`await` 的操作系统目标，以及已经能工作的代码：重写是一种成本，所以陷阱在于把它花在没有回报的地方。\n* **在接缝处迁移：** 用 continuation 包裹遗留回调，用现代方式写新代码，用 actor 替换临时性的锁，为 UI 采用 `@MainActor`，并逐步打开 Swift 6 的 data race 检查。\n* **小心地桥接边界：** 一个 continuation **恰好恢复一次**，所以一个触发很多次的回调需要一个 `AsyncStream`。而且永远不要在 `Task` 内部阻塞在 `DispatchGroup.wait()`/`semaphore.wait()` 上：用一个 continuation 桥接，并对它 `await`。\n* **`@MainActor` 不会移动你的慢速工作**：它保证被标注的代码在主线程上运行。在主线程之外的一个普通异步函数里做繁重的工作，把 `@MainActor` 的部分留给末尾那小小的 UI 更新。\n* 这两个模型可以**互操作**：混合代码在一次迁移期间是正常且预期之中的。\n\n---\n\n## 下一步去哪\n\n这就是整本书：从主线程上一个被阻塞的咖啡师，到在单个进程内保持共享状态安全的 actor。你已经认识了经典模型（GCD 和 Operations）和现代模型（`async`/`await`、结构化并发、`AsyncSequence` 和 actor），也看到了*为什么*第二个作为对第一个的回应而存在。\n\n这些概念只有在你把它们用在某件你在乎的事情上时，才会真正沉淀下来。所以这里是收尾的鼓励：**打开你自己的某个项目，重新回顾那些现代章节。** 找一个 completion handler，把它变成 `async`/`await`。找一个被锁守护的共享可变值，把它做成一个 `actor`。找一个会卡顿的界面，把它繁重的工作移出主线程。每一个小改动都会让某一章彻底地落到位。\n\n在你有意地、在你自己拥有的代码里让并发运转起来的那一刻，它就不再可怕了。去做吧。你准备好了。\n\n---\n\n## 附加曲目：跨机器的 actor\n\n好奇 actor 这个理念能延伸多远吗？在这一章之后还有一章，**[分布式 actor](Distributed%20Actors.playgroundchapter/Overview)**，作为额外学分。它把同样的“用 `await` 来调用”的感觉，带到活在*其他进程、甚至其他机器上*的对象。它是一个边读边看的概念之旅，而不是一个可运行的实验，所以当核心理念感觉扎实之后，把它当作一次向前的展望。\n\n[上一页](@previous)  |  第 8 / 8 页";
