引言

App 里做耗时计算(图片处理、数据解析、文件加密)如果不放后台线程,UI 直接卡死。HarmonyOS 提供了三种并发方案:TaskPoolWorker@Concurrent 装饰器

本篇帮你理清三者的区别,并给出实战代码。


一、三种并发方案对比

Worker

创建

手动管理

主线程

Worker线程

TaskPool

创建任务

自动回收

主线程

系统托管线程池

特性 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 装饰的函数必须是独立纯函数,不能访问外部变量
  • 参数和返回值必须是可序列化的(ArrayBufferstringnumber 等)
  • 不能操作 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。记住这个,鸿蒙并发不再纠结。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐