/* Page prose (zh-Hans) */
"TasksAreNotThreads" = "# 任务不是线程\n\n几乎每个开发者都会带着一个信念，现在值得把它忘掉，因为上面的一切都依赖于此：**创建一个任务并不会创建一个线程。**\n\n**线程** 是操作系统拥有的一种昂贵资源；它才是真正运行指令的东西，而你的机器只有区区几个核心来运行它们。**任务** 只是 *你* 描述的一个工作单元。这两者的体量根本不在一个量级：你可以创建成千上万个任务，但线程永远只会有一小撮。\n\n所以 Swift 维护一个小小的 **协作式线程池**（大约 **每个 CPU 核心一个线程**），并把你的任务 *多路复用* 到它上面。许多任务在少数几个线程上轮流执行。你无法挑选是哪个线程；系统替你调度工作，用每个任务的 **优先级** 作为先运行什么的提示（关于优先级的更多内容见章节 [任务与取消](Tasks%20and%20Cancellation.playgroundchapter/Overview)）。\n\n这正是挂起为什么重要的原因。当一个任务碰到 `await` 并挂起时，它 **把自己的线程交还给线程池**，于是另一个任务抓住那个线程并向前推进。当你的任务结果就绪时，它会在 *接下来空闲的任意* 池中线程上恢复，那可能是一个和它开始时 **不同** 的线程。（这就是为什么上面说“稍晚在某个线程上恢复”里用的是 *某个*。）\n\n```\nThe pool has ~4 threads. You made 100 tasks.\n\nTask A runs on thread 2 ──await──▶ suspends, releases thread 2\n                                       │\nTask B grabs thread 2 and runs ◀───────┘\n   ...\nTask A's result is ready ──▶ resumes on whatever thread is free (maybe thread 0)\n```\n\n要点是：不要想象每个 `Task { }` 背后都会冒出一个崭新的线程。想象少数几个繁忙的线程在彼此之间传递许多任务，每个任务每次 `await` 时都松开自己的线程。\n\n> **经典模型有着不同的脾性。** GCD 也运行在一个线程池上，但如果你 *阻塞* 它的线程（一次 `sync` 等待、一个信号量、一次 `Thread.sleep`），GCD 往往会创建 **更多** 线程来补偿，这个问题叫 **线程爆炸**，可能膨胀到数十个线程争抢同样的核心。现代线程池刻意拒绝这样做：它保持在大约核心数的上限，并依赖任务去 *挂起*（`await`）而不是 *阻塞*。就这一个差别（挂起，而非阻塞）很大程度上说明了 *为什么* 现代模型会存在，以及为什么在任务内部调用像 `Thread.sleep` 这样的阻塞 API 是个错误（章节 [任务与取消](Tasks%20and%20Cancellation.playgroundchapter/Overview) 展示了一个把线程扣为人质的例子）。\n\n[上一页](@previous)  |  第 4 / 8 页  |  [下一页: 在异步上下文中 await](@next)";
