【HarmonyOS NEXT】多线程并发-taskpool
鸿蒙系统TaskPool多线程方案解析:TaskPool是鸿蒙提供的轻量级多线程方案,开发者只需用@Concurrent标记耗时函数即可提交后台执行,系统自动管理线程生命周期。使用流程包括定义任务、提交执行和处理结果,注意任务需满足无状态、参数可序列化且不操作UI。适用于短耗时(≤5秒)、无状态、高并发及优先级敏感的任务场景,如数据计算、批量检查等,能有效提升性能而不阻塞UI线程。
一、背景
在鸿蒙开发中提供了两种多线程并发方案,分别是TaskPool与Worker,此篇文章主要总结下TaskPool
二、TaskPool概念
1、TaskPool是为应用提供多线程运行环境,旨在降低资源消耗并提升系统性能
2、开发者无需关心线程的生命周期,由系统统一管理线程的创建、调度和销毁
3、目标:简化「轻量、短期、独立任务」的异步执行,解决开发者手动管理线程的繁琐性和资源浪费问题

三、注意事项
1、装饰器:仅支持在.ets文件中使用
A、实现任务的函数需要使用@Concurrent装饰器
B、从API version 11开始,跨并发实例传递带方法的实例对象时,该类必须使用装饰器@Sendable装饰器
2、耗时要求
A、在TaskPool工作线程中的执行时长不能超过3分钟(LongTask除外)
B、可通过Task的属性ioDuration、cpuDuration获取执行当前任务的异步IO耗时和CPU耗时
3、任务函数的入参类型
A、入参需满足序列化支持的类型
B、目前不支持使用@State装饰器、@Prop装饰器、@Link装饰器等装饰器修饰的复杂类型
4、ArrayBuffer参数
A、默认转移,需要设置转移列表可通过接口setTransferList()设置
B、若要多次使用ArrayBuffer,可通过setCloneList()改为拷贝传递
5、模块使用限制
A、只能使用线程安全的模块,不能使用UI相关的非线程安全模块,只支持在主线程中使用的模块(ApplicationContext)
B、不支持在线程中使用AppStorage
6、其他注意项
A、序列化传输的数据量限制为16MB
B、Promise不支持跨线程传递
C、不支持指定任务所运行的线程,任务会被分配到空闲的线程中执行
D、IDLE 优先级任务仅在所有线程空闲时执行,且同一时间只执行一个
四、怎么用
使用TaskPool流程:定义任务 → 提交任务 → 处理结果 → 取消任务(可选)
步骤一:定义耗时任务(必须用 @Concurrent 标记)
所有提交到 TaskPool 的耗时函数,必须通过 @Concurrent 装饰器标记——这是鸿蒙的强制要求,用于告知系统“该函数是耗时任务,需在后台线程执行”。
注意:该函数需满足「无状态、参数可序列化」,不能直接操作 UI(如修改 @State 变量、调用 UI 组件方法)。
@Concurrent
function computeTask(a: number, b: number): number {
let start = Date.now();
while (Date.now() - start < 2000) {
} // 阻塞2秒(后台线程,不影响UI)
return a + b;
}
步骤二、提交任务+处理结果
创建 Task 实例,将函数和参数包装起来;提交到任务池执行,并等待 Promise 返回的结果
export class taskpoolUtils {
private static instance: taskpoolUtils | undefined;
public static getInstance(): taskpoolUtils {
if (!taskpoolUtils.instance) {
taskpoolUtils.instance = new taskpoolUtils();
}
return taskpoolUtils.instance;
}
async runConcurrentTask() {
try {
// 1. 同步创建Task实例
const task: taskpool.Task = new taskpool.Task(computeTask, 10, 20);
// 2. 提交任务到后台线程
const result = await taskpool.execute(task);
console.log('lucy== 计算结果result', result); // 2秒后打印30
} catch (err) {
// 捕获任务执行异常
console.error('lucy== 任务执行失败', JSON.stringify(err));
}
}
}
最终效果执行
import { ScreenUtils } from '../utils/ScreenUtils';
import { taskpoolUtils } from '../utils/taskpoolUtils'
@Entry
@Component
struct Index {
private globalNavStack: NavPathStack = new NavPathStack();
//UI状态,验证taskpool不阻塞UI
@State uiText: string = '未执行任务';
build() {
Column() {
Navigation(this.globalNavStack) {
// 显示UI状态,验证是否阻塞
Text(this.uiText).fontSize(20).margin(20);
Button('跳转到login组件+执行耗时任务')
.onClick(() => {
// 1. 先更新UI(验证UI线程没被阻塞)
this.uiText = '任务执行中...';
// 2. 跳转页面(UI操作)
this.globalNavStack.pushPathByName('loginPage', null, false);
// 3. 执行taskpool耗时任务
taskpoolUtils.getInstance().runConcurrentTask().then(() => {
// 任务完成后更新UI
this.uiText = '任务执行完成';
});
// 4. 验证:任务执行中,UI仍能响应(立即打印,不会等2秒)
console.log('lucy== UI线程未阻塞,立即执行');
})
}
.height('100%')
.width('100%')
.padding({ top: ScreenUtils.getInstance().getStatusBarHeight() })
}
}
}
五、实战场景
使用 TaskPool 流程:定义任务 → 提交任务 → 处理结果 → 取消任务(可选)
5.1、项目背景
项目中使用taskpool实现插件下载的功能,结合实际项目代码来梳理下 TaskPool 流程
5.2、具体步骤
步骤1:定义耗时任务
必须用 @Concurrent 标记,支持 @Sendable 传递复杂对象

补充:@Sendable 标记复杂传递对象

步骤2:提交任务 + 处理结果
创建 Task 实例包装耗时函数与参数,提交到 TaskPool 执行,并通过 then/catch 处理结果 / 异常;支持配置任务优先级,还可通过 onReceiveData 接收后台任务的中间通信数据。

六、适用场景
A、短耗时任务:执行时间建议 ≤ 5 秒(如缓存检查、MD5 校验、小型数据计算、接口参数加密);
B、无状态任务:任务执行不依赖外部状态,多次执行结果一致(如相同参数的 MD5 计算,结果始终相同);
C、高并发任务:需要同时执行多个独立任务(如批量下载多个小插件的前置检查);
D、优先级敏感任务:不同任务有优先级差异(如用户主动触发的下载 > 后台自动更新)。
更多推荐




所有评论(0)