/* Page prose (zh-Hans) */
"FanningOutWithTaskGroup" = "# 用 `withTaskGroup` 扇出\n\n你用 `withTaskGroup(of:)` 打开一个 group，告诉它每个子任务将返回的类型。在里面，你为每个元素调用一次 `group.addTask { ... }`（想调用多少次都行），然后用 `for await` 遍历这个 group 来读取结果。";
"FanningOutWithTaskGroup-2" = "仔细读一读它的结构，因为这就是整章的核心：\n\n* `withTaskGroup(of: Double.self)` 打开这个 group。`Double` 是每个子任务返回的类型：这里是一帧的亮度。\n* `group.addTask { ... }` 调度一个**子任务**。每个子任务都与它的兄弟并发运行，并且每个都返回一个 `Double`。\n* `for await brightness in group` **在结果完成时逐个**把它们取出来。这个 group 是一个由其子任务返回值构成的 `AsyncSequence`。\n* 你从闭包里 `return` 的值会成为整个 `await withTaskGroup(...)` 表达式的结果。\n\n为了体会它的好处，把它和按顺序运行同样的工作对比一下，也就是在下一帧开始之前先 await 每一帧：";
"FanningOutWithTaskGroup-3" = "顺序版本在开始下一帧之前会先 await 每一帧，所以 8 帧、每帧半秒，大约要花 **4 秒**。上面的 task group 版本则一次性启动全部 8 帧，所以它们会重叠，整批大约在**半秒**内完成。\n\n* callout(试一试): 把上面代码里的 `frameCount` 提到 `40` 再重新运行；并行时间几乎没变。相比之下，对 40 帧做一个普通的顺序循环则会攀升到接近 20 秒。\n\n留意*为什么*即使你的设备只有区区几个核心，这些工作也能重叠：这里每一帧大部分时间都在**等待**（那个 `Task.sleep` 代表读取一个文件），而且，正如你在 [为什么需要并发](Why%20Concurrency.playgroundchapter/Overview) 这一章看到的，等待中的任务会彼此让路。真正的校准也是 CPU 工作，在那种情况下，group 还会让系统把各帧分散到现有的任意核心上。无论哪种情况，group 都把一堆彼此独立的工作变成了一个并发的批次。\n\n[上一页](@previous)  |  第 3 / 9 页  |  [下一页: 结果按完成顺序到达](@next)";
