文章目录
- 前言
- 它们解决同一件事
- 决策树(直接对号入座)
- TaskPool 骨架(回顾)
- 代码实现
- Worker 骨架
- 核心代码
- 对比总表
- 常见误区(小白必踩)
- 完整可运行示例:TaskPool vs Worker
- 完整示例
- 写在最后
前言
前面讲 TaskPool 那篇说过,HarmonyOS 后台干活有两套:TaskPool和Worker。它们都能把重活丢出主线程,但设计哲学不同。
经常有人问:"我到底该用哪个?"这篇文章不啰嗦,直接给你决策树 + 对比 + 各自的代码骨架,你照着对号入座。
它们解决同一件事
主线程不能卡,重活要后台跑。TaskPool 和 Worker 都是"后台线程"的实现,区别在于怎么管理线程:
- TaskPool:线程池,你只管扔任务,池子帮你调度、复用线程。
- Worker:你手动 new 一个独立线程,长期驻留,自己管生命周期。
决策树(直接对号入座)
你的后台逻辑是? ├─ 跑一次、算完就完、要结果回来? │ → 用 TaskPool(简单、省心) ├─ 需要长期驻留、反复双向通信? │ → 用 Worker(如常驻音视频处理线程) ├─ 任务特别多、零散、短? │ → 用 TaskPool(池化复用,不爆线程) └─ 要和主线程持续"聊天"(发消息来回)? → 用 Worker(message 通信)TaskPool 骨架(回顾)
适合"一次性重计算":
代码实现
import{taskpool}from'@kit.ExecutionKit'functioncalc(n:number):number{/* 耗时 */returnn*2}consttask=newtaskpool.Task(calc,1000000)constresult=awaittaskpool.execute(task)特点:顶层函数、参数可序列化、execute返回 Promise。用完即弃,不用管线程。
Worker 骨架
适合"常驻、持续通信":
核心代码
// worker 文件(独立线程逻辑)import{worker}from'@kit.ArkTS'constparent=worker.workerPort parent.onmessage=(e)=>{constres=heavyProcess(e.data)// 处理主线程发来的数据parent.postMessage(res)// 把结果发回去}// 主线程constw=newworker.ThreadWorker('entry/ets/workers/myworker.ts')w.onmessage=(e)=>{console.info('收到结果',e.data)}w.postMessage({cmd:'start',payload:data})// 发任务给 worker要点:
- Worker 是独立文件(
myworker.ts),里面写后台逻辑。 - 双方程序通过
postMessage/onmessage互相发消息,可反复通信。 - 用完要
w.terminate()销毁,否则线程一直占着。
对比总表
| 维度 | TaskPool | Worker |
|---|---|---|
| 生命周期 | 池化,自动回收 | 手动 new/terminate |
| 通信 | 只回最终结果 | 持续双向 message |
| 代码位置 | 顶层函数 | 独立 worker 文件 |
| 适用 | 短任务、批处理 | 长驻、常通信 |
常见误区(小白必踩)
| 误区 | 说明 |
|---|---|
| 长驻常通信却用 TaskPool | TaskPool 用完即弃,需要持续双向通信得上 Worker。 |
| 一次性计算硬开 Worker | Worker 生命周期重,单次重计算用 TaskPool 更省心。 |
Worker 不terminate | 用完不销毁,线程一直占着资源。 |
下面这段代码可以直接复制到 DevEco Studio 里运行。建议你边读边敲,改一改文末「动手改一改」里的参数,亲眼看看效果。
完整可运行示例:TaskPool vs Worker
短任务用 TaskPool,长驻任务用 Worker。
完整示例
// TaskPool:派发一次性任务,自动回收import{taskpool}from'@kit.ArkTS'@ConcurrentfunctionshortTask(n:number):number{returnn*2}// Worker:长驻后台,可反复收发消息// worker.tsimport{worker}from'@kit.ArkTS'constparent=worker.workerPort parent.onmessage=(e)=>{parent.postMessage(e.data*2)}你会看到什么:TaskPool适合「派出去、拿结果、完事」的短任务,无需手动管理生命周期;Worker适合需要长期驻留、反复通信的场景(如持续定位)。两者都不阻塞 UI 线程。
动手改一改:
- 把一次性计算从 Worker 改用 TaskPool,体会代码量差异。
- 给 Worker 增加「心跳」消息,维持长连接。
- 用 TaskPool 的
taskpool.execute串行/并行组合做流水线。
写在最后
选型记住:一次性计算 → TaskPool;长驻常通信 → Worker。绝大多数"卡 UI 的计算"用 TaskPool 就够了,别上来就开 Worker——Worker 的生命周期和通信管理更重,用错了反而添乱。
回去看看你项目里那些"主线程重活",先判断"是一次性的还是常驻的",对号入座选一个。90% 的情况,TaskPool 是答案。