HarmonyOS的TaskPool vs Worker还在纠结?鸿蒙并发编程选型+实战一篇讲透
·
引言
App 里做耗时计算(图片处理、数据解析、文件加密)如果不放后台线程,UI 直接卡死。HarmonyOS 提供了三种并发方案:TaskPool、Worker、@Concurrent 装饰器。
本篇帮你理清三者的区别,并给出实战代码。
一、三种并发方案对比
| 特性 | TaskPool | Worker | @Concurrent |
|---|---|---|---|
| 创建方式 | API 调用 | 独立 .ets 文件 | 函数装饰器 |
| 线程管理 | 系统自动 | 手动创建/销毁 | 系统自动 |
| 通信方式 | 函数调用+返回值 | postMessage 消息 | 函数调用 |
| 适用场景 | 短耗时计算 | 长生命周期任务 | 简单并行函数 |
| 复杂度 | 低 | 高 | 最低 |
二、TaskPool:推荐的首选方案
TaskPool 是鸿蒙推荐的并发方案,系统帮你管理线程池,用完自动回收。
2.1 基本用法
import taskpool from '@ohos.taskpool';
// 定义一个耗时任务函数
@Concurrent
function computePrimeCount(limit: number): number {
let count = 0;
for (let i = 2; i <= limit; i++) {
let isPrime = true;
for (let j = 2; j * j <= i; j++) {
if (i % j === 0) { isPrime = false; break; }
}
if (isPrime) count++;
}
return count;
}
// 提交任务
async function runTask() {
const task = new taskpool.Task(computePrimeCount, 1000000);
const result = await taskpool.execute(task);
console.log('质数个数:', result);
}
2.2 多个参数
@Concurrent
function processImage(data: ArrayBuffer, quality: number, format: string): ArrayBuffer {
// 模拟图片处理
console.log(`处理图片: quality=${quality}, format=${format}`);
return data;
}
const task = new taskpool.Task(processImage, buffer, 80, 'jpeg');
const result = await taskpool.execute(task);
2.3 注意事项
- 被
@Concurrent装饰的函数必须是独立纯函数,不能访问外部变量 - 参数和返回值必须是可序列化的(
ArrayBuffer、string、number等) - 不能操作 UI,不能使用
Context
三、Worker:长生命周期的选择
Worker 适合 WebSocket 长连接、后台轮询等需要长期存在的后台任务。
3.1 创建 Worker 文件
workers/image_worker.ets:
import worker from '@ohos.worker';
const workerPort = worker.workerPort;
// 监听主线程消息
workerPort.onmessage = (e: MessageEvent) => {
const { type, data } = e.data;
if (type === 'resize') {
// 执行图片缩放
const result = doResize(data.buffer, data.width, data.height);
workerPort.postMessage({ type: 'done', result });
}
};
function doResize(buffer: ArrayBuffer, w: number, h: number): ArrayBuffer {
// 模拟图片处理耗时
return buffer;
}
3.2 主线程使用 Worker
import worker from '@ohos.worker';
// 创建 Worker
const wk = new worker.ThreadWorker('entry/ets/workers/image_worker.ets');
// 发送消息
wk.postMessage({ type: 'resize', data: { buffer, width: 800, height: 600 } });
// 接收结果
wk.onmessage = (e: MessageEvent) => {
console.log('处理完成:', e.data);
};
// 销毁
wk.terminate();
四、@Concurrent:最简单的并行
对于不需要复杂通信的纯计算任务,直接用 @Concurrent 装饰器:
@Concurrent
function fibonacci(n: number): number {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
@Concurrent
function hashString(input: string): string {
let hash = 0;
for (let i = 0; i < input.length; i++) {
hash = ((hash << 5) - hash) + input.charCodeAt(i);
hash |= 0;
}
return hash.toString(16);
}
// 直接调用
const result = await fibonacci(40);
@Concurrent 会自动将函数放到后台线程执行,返回 Promise。
五、选型决策指南
渲染错误: Mermaid 渲染失败: Parse error on line 5: ...✅] B -->|简单纯函数| E[@Concurrent ✅] ----------------------^ Expecting 'AMP', 'COLON', 'DOWN', 'DEFAULT', 'NUM', 'COMMA', 'NODE_STRING', 'BRKT', 'MINUS', 'MULT', 'UNICODE_TEXT', got 'LINK_ID'
| 场景 | 推荐方案 |
|---|---|
| 图片压缩/滤镜处理 | TaskPool |
| JSON 大文件解析 | TaskPool |
| WebSocket 长连接 | Worker |
| 后台数据同步 | Worker |
| 加密/哈希计算 | @Concurrent |
| 数组排序/搜索 | @Concurrent |
六、避坑指南
⚠️ 常见错误
// ❌ 错误:@Concurrent 函数不能使用外部变量
const config = { threshold: 100 };
@Concurrent
function process(items: number[]) {
return items.filter(i => i > config.threshold); // 编译报错!
}
// ✅ 正确:参数传递
@Concurrent
function process(items: number[], threshold: number) {
return items.filter(i => i > threshold);
}
⚠️ 序列化限制
// ❌ 不能传递 Function、Symbol、循环引用对象
// ✅ 可以传递:number, string, boolean, ArrayBuffer, 普通对象, 数组
⚠️ 不要滥用并发
并发不是银弹。对于 1ms 就能完成的操作,创建线程的开销比执行时间还大。只有超过 100ms 的耗时操作才值得开并发。
总结
TaskPool → 短耗时计算,系统托管,推荐首选
Worker → 长生命周期,手动管理,需独立文件
@Concurrent → 纯函数并行,最简单,限制最多
选型口诀:短用 TaskPool,长老 Worker,简单 @Concurrent。记住这个,鸿蒙并发不再纠结。
更多推荐



所有评论(0)