鸿蒙 多线程并发-TaskPool
摘要: ArkTS的TaskPool提供简化的多线程管理机制,通过自动扩缩容(最大线程数由设备核数决定)优化性能。任务需用@Concurrent装饰器标记,支持序列化参数/返回值,执行时长限制3分钟。关键约束包括:禁止UI操作、使用线程安全模块、数据传输量≤16MB。适用于CPU密集型/I/O异步短任务,长任务推荐Worker。@Concurrent函数规范严格,支持Promise,跨线程类需@S
本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
一、TaskPool 概念
-
TaskPool 是 ArkTS 提供的多线程环境,用于在应用程序中执行并发任务,旨在降低资源消耗、提升系统性能。
-
开发者无需管理线程生命周期,由系统统一管理线程的创建、调度和销毁。
二、运作机制
1. 基本流程
-
提交任务:宿主线程将任务提交到任务队列。
-
系统调度:系统根据负载情况选择合适的工作线程执行任务。
-
返回结果:任务执行完成后,将结果返回给宿主线程。
2. 线程管理特性
-
默认启动一个工作线程,任务增多时自动扩容。
-
最大线程数由设备物理核数决定。
-
空闲时自动缩容,减少线程数量以节省资源。
-
支持任务优先级、任务取消等控制。
三、使用注意事项
1. 函数装饰器要求
-
任务函数必须使用
@Concurrent装饰器标注,且只能在 .ets 文件中使用。 -
从 API 11 开始,跨线程传递带方法的类必须使用
@Sendable装饰器。
2. 执行时长限制
-
任务在 TaskPool 中的同步执行时间不能超过 3 分钟(不包括异步等待时间)。
-
可通过
Task的ioDuration、cpuDuration属性获取 I/O 和 CPU 耗时。
3. 参数与返回值类型
-
任务函数的参数和返回值必须支持序列化。
-
不支持使用
@State、@Prop、@Link等装饰的复杂类型。
4. ArrayBuffer 传输方式
-
默认是转移(Transfer),可通过
setTransferList()设置。 -
如需多次使用同一 ArrayBuffer,应使用
setCloneList()改为拷贝传递。
5. 模块使用限制
-
TaskPool 工作线程只能使用线程安全的模块。
-
不支持 UI 操作、非线程安全模块、以及仅支持主线程的模块(如
ApplicationContext)。 -
不支持在 TaskPool 中使用
AppStorage。
6. 其他限制
-
序列化数据量限制为 16MB。
-
Promise 不支持跨线程传递,返回 pending 或 rejected 状态会失败。
-
不支持指定运行线程,任务由系统分配至空闲线程。
-
IDLE 优先级任务仅在所有线程空闲时执行,且同一时间只执行一个。
四、@Concurrent 装饰器
1. 使用规范
| 项目 | 说明 |
|---|---|
| 装饰器参数 | 无 |
| 使用场景 | 仅 Stage 模型、.ets 文件 |
| 支持的函数类型 | async 函数、普通函数(不支持 generator、箭头函数、类方法、匿名函数) |
| 变量访问 | 允许:局部变量、入参、import 变量;禁止:闭包变量 |
| 返回值类型 | 必须支持序列化 |
2. 示例
1:基本并发函数
import { taskpool } from '@kit.ArkTS';
@Concurrent
function computeSum(a: number, b: number): number {
return a + b;
}
async function runConcurrentTask(): Promise<void> {
const task = new taskpool.Task(computeSum, 10, 20);
const result = await taskpool.execute(task);
console.info(`计算结果: ${result}`); // 输出:计算结果: 30
}
2:并发函数返回 Promise
@Concurrent
async function fetchData(id: number): Promise<string> {
return await new Promise((resolve) => {
setTimeout(() => {
resolve(`Data for id: ${id}`);
}, 500);
});
}
async function runAsyncTask(): Promise<void> {
const task = new taskpool.Task(fetchData, 1001);
const data = await taskpool.execute(task);
console.info(`获取数据: ${data}`);
}
3:使用外部定义的类和函数
// utils.ets
export function processValue(val: number): number {
return val * 2;
}
@Sendable
export class DataProcessor {
process(input: string): string {
return `Processed: ${input}`;
}
}
// main.ets
import { taskpool } from '@kit.ArkTS';
import { processValue, DataProcessor } from './utils';
@Concurrent
function runExternalLogic(): string {
const value = processValue(5); // 正确:使用导入函数
const processor = new DataProcessor(); // 正确:使用导入的 @Sendable 类
return processor.process(`value is ${value}`);
}
五、TaskPool 扩缩容机制
1. 扩容条件
-
当任务队列中有新任务提交,且当前空闲线程数小于待执行任务数时触发扩容。
-
系统根据负载计算所需线程数并创建新工作线程。
2. 缩容条件
-
每 30 秒检测一次负载。
-
释放线程需满足:
-
空闲时间 ≥ 30 秒;
-
未执行
LongTask; -
无未释放的句柄(如 Timer);
-
非调试状态;
-
无未销毁的子 Worker。
-
六、适用场景
-
适用:短时任务、无状态任务、CPU 密集型计算、I/O 异步处理。
-
不适用:长时任务(超过3分钟)、需指定线程、需操作 UI 的任务(推荐使用 Worker)。
更多推荐



所有评论(0)