/* Page prose (zh-Hans) */
"DispatchGroupFinishLine" = "# `DispatchGroup`：多个任务的终点线\n\n**`DispatchGroup`** 是一个计数器，它跟踪一组任务，让你能在整组完成时收到通知。你用 `enter()` 标记一个任务加入这个组，用 `leave()` 标记它已完成。当 `leave()` 的调用次数追上 `enter()` 的调用次数时（此时组为**空**），组就会触发。";
"DispatchGroupFinishLine-2" = "`notify(queue:)` 是关键的一行：它注册一个代码块，在组变空的那一刻，**稍后**在你指定的队列上运行。它**不会**阻塞。你的代码会径直越过它继续往下流动。\n\n**观察运行：** 有两点要留意。第一，`📤 Batch sent...` 会在任何饮品之前打印；`notify` 没有阻塞。第二，饮品是按**完成顺序**出现的（先 cold brew，然后 espresso，再 latte），*而不是*你启动它们的顺序，这正是前一章的那个教训。但托盘那一行总是**最后**出现，在三杯全部之后，因为组等待了每一次 `leave()`。这就是全部意义所在：无论任务以什么顺序完成，你都能得到一个干净利落的“全部完成”回调。\n\n* callout(试一试): 交换冲煮时间，让 Latte 为 `0.1`、Cold brew 为 `0.9`。饮品会重新排序，但托盘那一行还会落在最后吗？\n\n> 当工作是一个普通的 `async` 闭包时，你可以省去手动配对，让队列替你保持平衡：`barista.async(group: group) { ... }`。这是一个**快捷方式**，它在你的代码块之前调用 `enter()`，在之后调用 `leave()`。当“完成”的时刻是一个稍后才触发的*回调*（比如网络 completion handler）、没有哪一个单独的闭包其结束就意味着“完成”时，才使用手动的 `enter()`/`leave()`。\n\n[上一页](@previous)  |  第 3 / 8 页  |  [下一页: wait()：会阻塞的替代方案](@next)";
