6-12.【多线程】Worker 创建成本是多少?是否支持协程调度器?

3 阅读3分钟

在 ArkTS 的并发体系中,Worker 的定位是“重量级后台线程”,而对于开发者关心的协程,ArkTS 有一套独特的实现逻辑。


1. Worker 的创建成本有多高?

由于 ArkTS 采用 Actor 内存隔离模型,创建一个 Worker 的成本显著高于传统 Java/C++ 线程:

  • 独立的 ArkTS 引擎实例:每个 Worker 启动时,系统都会为其分配一个完全独立的虚拟机实例(ArkTS Runtime)。这意味着它有自己的指令执行器、堆栈空间和辅助线程。
  • 内存开销(Memory Cost) :创建一个空的 Worker 大约会占用 2MB ~ 5MB 的物理内存。如果 Worker 中加载了复杂的业务代码或第三方库,这个数字会迅速上升。
  • 时间开销(Time Cost) :Worker 的启动涉及二进制字节码的加载、运行环境初始化等。在高负载环境下,启动一个 Worker 可能需要 50ms ~ 100ms
  • 数量限制:系统目前限制单个应用进程同时运行的 Worker 数量(API 11 之后限制提升至 64 个,但建议保持在 8 个以内)。

结论: Worker 绝不适合“即用即建”。它应该用于长生命周期、常驻型的任务。对于短促的任务,请务必使用 TaskPool,它底层实现了线程池复用,创建成本几乎为零。


2. 是否支持协程调度器?

结论:ArkTS 并不提供像 Kotlin/Go 那样的原生“协程(Coroutine)”调度器,但它通过 async/await 实现了类似的异步非阻塞效果。

在 HarmonyOS 的架构中,开发者感知到的“异步”其实是由 微任务(Microtask) 驱动的:

A. 它是如何运作的?

当你调用一个 async 函数并 await 时:

  1. 当前函数会被挂起(Suspend)
  2. 线程不会阻塞,它会回到 Event Loop(事件循环) 去处理其他任务(如 UI 渲染)。
  3. 当异步操作完成后,结果会作为一个微任务加入队列,主线程在空闲时恢复执行该函数。

B. 为什么没有独立的“协程调度器”?

  • 单线程事件循环:在 ArkTS 的主线程中,只有一个调度核心,即事件循环。它不需要像多线程协程那样在多个物理线程间切换上下文(Context Switch)。
  • 任务分流机制:如果你需要真正的并行处理,ArkTS 引导你使用 TaskPool。TaskPool 底层有一个名为 FFRT(Function Flow Runtime) 的调度框架,它实际上扮演了“原生级协程调度器”的角色,自动管理着物理线程池,并将你提交的任务均匀分配到 CPU 核心。

3. Worker vs TaskPool 选型决策表

特性WorkerTaskPool (类似协程池)
创建成本极高 (独立虚拟机)极低 (线程池复用)
通信方式持续的双向消息流 (postMessage)基于结果的单次返回 (Promise)
任务上限受系统硬限制 (64个)无固定上限,系统自动调节
适用场景长时运行(如 Socket、持续下载)短时并行(如 JSON 解析、图像计算)
调度能力开发者手动调度系统级 FFRT 自动调度 (QoS)

性能调优建议:

  1. 禁忌操作:严禁在 for 循环中频繁 new Worker()
  2. TaskPool 优先:除非你需要跨越多个生命周期维持一个长连接,否则 90% 的并发场景应优先考虑 TaskPool。
  3. 协程陷阱:记住 async/await 只是把任务排队,它并不能让主线程的同步计算变快。如果你的循环计算耗时,await 也会卡死 UI。