本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
一、线程的实现方式
鸿蒙提供了多种线程管理方案,适用于不同场景:
1. 基于ArkTS/JS的异步任务(TaskPool)
- 用途:执行CPU密集型任务(如数据处理、图像解码)。
- 特点:
- 轻量级线程池(TaskPool)管理,自动调度。
- 任务之间隔离,崩溃不影响主线程。
- 示例:
import taskpool from '@ohos.taskpool';
@Concurrent
function computeTask(data: number): number {
return data * 2; // 在子线程中执行
}
async function runTask() {
const task = new taskpool.Task(computeTask, 100);
const result = await taskpool.execute(task); // 提交到线程池
console.log(`Result: ${result}`);
}
关键点:
@Concurrent
装饰器是必须的,表示该函数可并发执行。- 任务参数需可序列化(不支持回调函数、类实例等)。
2. Worker线程
- 用途:长时间运行的后台任务(如网络请求、文件IO)。
- 特点:
- 独立线程,与主线程通过消息通信。
- 需单独创建
worker.ts
文件。
- 示例:
步骤1:创建Worker文件 在entry/src/main/ets/workers
目录下创建FileWorker.ts
:
// workers/FileWorker.ts
import worker from '@ohos.worker';
// 1. 获取Worker通信端口
const workerPort = worker.workerPort;
// 2. 监听主线程消息
workerPort.onmessage = (msg: MessageEvents) => {
console.log(`Worker收到消息: ${JSON.stringify(msg.data)}`);
// 模拟耗时操作(如文件处理)
setTimeout(() => {
workerPort.postMessage({ status: 'done', result: msg.data * 2 }); // 返回结果
}, 1000);
};
// 3. 错误处理
workerPort.onerror = (err: ErrorEvent) => {
console.error(`Worker发生错误: ${err.message}`);
};
步骤2:主线程调用
// 主线程代码
const worker = new worker.ThreadWorker('entry/ets/workers/FileWorker.ts');
// 1. 发送消息到Worker
worker.postMessage(42); // 传递数据
// 2. 接收Worker返回结果
worker.onmessage = (msg: MessageEvents) => {
console.log(`主线程收到结果: ${JSON.stringify(msg.data)}`);
// 输出: 主线程收到结果: {"status":"done","result":84}
};
// 3. 销毁Worker(不再需要时)
worker.terminate();
关键点:
- Worker文件路径需相对于
entry/src/main/ets
。 - 通过
postMessage
和onmessage
实现双向通信。
二、线程间通信(IPC)方式
1. 消息传递(Worker/TaskPool)
- 机制:基于序列化数据的跨线程消息。
- 适用场景:ArkTS/JS层线程通信。
方法 | 说明 | 示例 |
---|---|---|
postMessage | 发送消息 | worker.postMessage({key: value}) |
onmessage | 接收消息 | worker.onmessage = (msg) => {} |
terminate | 终止Worker | worker.terminate() |
2. 共享内存(SharedArrayBuffer)
- 机制:多线程直接读写同一块内存。
- 注意:需手动同步避免竞态条件。
// 主线程
const sharedBuffer = new SharedArrayBuffer(16);
const intArray = new Int32Array(sharedBuffer);
// 线程A写入
Atomics.store(intArray, 0, 123);
// 线程B读取
const value = Atomics.load(intArray, 0);
console.log(value); // 输出: 123
注意:必须使用Atomics
API避免竞态条件。
3. 事件通知(Emitter)
- 机制:通过事件总线跨线程触发回调。
import emitter from '@ohos.events.emitter';
// 线程A发布事件
emitter.emit({
eventId: 1, // 事件ID
priority: emitter.EventPriority.HIGH // 优先级
}, {
data: { key: 'value' } // 事件数据
});
// 线程B订阅事件
emitter.on(1, (eventData) => {
console.log(`收到事件: ${eventData.data.key}`);
});
三、线程与通信的选择策略
场景 | 推荐方案 | 原因 |
---|---|---|
短时CPU密集型任务 | TaskPool | 自动管理,避免频繁创建线程 |
长时后台任务(如下载) | Worker | 隔离性强,崩溃不影响主线程 |
高性能计算(如音视频) | Native线程 + 共享内存 | 减少序列化开销,提升速度 |
跨进程通信 | RPC或分布式能力 | 鸿蒙专为跨设备设计 |
四、注意事项
1. 常见问题
-
问题1:Worker文件路径错误 解决:确保路径为
entry/ets/workers/文件名.ts
。 -
问题2:TaskPool任务参数不可序列化 解决:仅传递基本类型、数组、普通对象。
2. 性能优化
- 减少通信次数:合并多次
postMessage
为批量操作。 - 共享内存:大数据传输优先用
SharedArrayBuffer
。