在鸿蒙(HarmonyOS)开发中,TaskPool 和 Worker 是多线程编程的核心工具,用于提升应用性能、避免主线程阻塞。它们的核心区别在于任务粒度和资源管理:
特性 | TaskPool | Worker |
---|---|---|
适用场景 | 轻量级、短期、无状态任务 | 长时间、复杂、需状态保持的任务 |
线程管理 | 动态线程池,自动调度 | 独立线程,需手动创建/销毁 |
通信开销 | 低(参数传递简单) | 高(需序列化/反序列化消息) |
任务依赖 | 支持任务组、依赖关系 | 独立运行,无直接依赖 |
资源占用 | 共享线程池,资源复用 | 独立线程,占用固定资源 |
TaskPool 使用场景案例
场景 1:批量图片压缩(并行处理)
需求:用户选择多张图片后,并行压缩并显示结果。
选择理由:轻量级任务,无状态依赖,适合动态调度。
// 使用 TaskPool 并行压缩图片
import taskpool from '@ohos.taskpool';
// 定义压缩任务函数(需标记为并发函数)
@Concurrent
async function compressImage(imagePath: string): Promise<string> {
// 模拟压缩逻辑(实际调用图像处理API)
await new Promise(resolve => setTimeout(resolve, 500));
return `${imagePath}_compressed.jpg`;
}
// 主线程调用
async function processImages() {
const imagePaths = ['image1.jpg', 'image2.jpg', 'image3.jpg'];
// 创建任务组
const tasks: taskpool.Task[] = imagePaths.map(path =>
new taskpool.Task(compressImage, path)
);
// 并行执行并等待结果
const results = await taskpool.execute(tasks);
console.log('压缩完成:', results); // ['image1_compressed.jpg', ...]
}
场景 2:数据分片计算(任务组依赖)
需求:将大数据集分片计算,合并结果。
选择理由:利用任务组自动调度,减少手动线程管理。
@Concurrent
function calculateChunk(dataChunk: number[]): number {
return dataChunk.reduce((sum, num) => sum + num, 0);
}
async function processBigData() {
const bigData = Array.from({length: 1000}, (_, i) => i + 1);
const chunkSize = 100;
const tasks: taskpool.Task[] = [];
for (let i = 0; i < bigData.length; i += chunkSize) {
const chunk = bigData.slice(i, i + chunkSize);
tasks.push(new taskpool.Task(calculateChunk, chunk));
}
const partialSums = await taskpool.execute(tasks);
const total = partialSums.reduce((a, b) => a + b, 0);
console.log('总和:', total); // 应输出 500500
}
Worker 使用场景案例
场景 1:实时音视频处理(长时任务)
需求:持续接收麦克风数据并进行实时降噪处理。
选择理由:需要长期占用线程,维护处理算法状态。
// worker.ts
import worker from '@ohos.worker';
let noiseSuppressor: AudioProcessor; // 假设有音频处理类
workerPort.onmessage = (e: MessageEvents) => {
const audioData: Int16Array = e.data;
// 初始化处理器(仅一次)
if (!noiseSuppressor) {
noiseSuppressor = new AudioProcessor();
}
// 处理并返回结果
const processed = noiseSuppressor.process(audioData);
workerPort.postMessage(processed);
};
// 主线程使用 Worker
import worker from '@ohos.worker';
const audioWorker = new worker.ThreadWorker('workers/audio_worker.js');
// 接收处理后的音频数据
audioWorker.onmessage = (e: MessageEvents) => {
const processedData = e.data;
// 更新UI或播放音频
};
// 发送原始数据(如从麦克风获取)
function sendAudioDataToWorker(rawData: Int16Array) {
audioWorker.postMessage(rawData);
}
场景 2:数据库事务管理(状态敏感任务)
需求:在后台执行复杂数据库事务(如数据迁移)。
选择理由:需要保持数据库连接状态,避免多次开关。
// worker.ts
import worker from '@ohos.worker';
import relationalStore from '@ohos.data.relationalStore';
let db: relationalStore.RdbStore; // 数据库连接
workerPort.onmessage = async (e: MessageEvents) => {
const { type, sql, params } = e.data;
if (type === 'init') {
// 初始化数据库连接
const config = { name: 'mydb.db' };
db = await relationalStore.getRdbStore(globalThis.context, config);
} else if (type === 'exec') {
// 执行SQL语句
await db.executeSql(sql, params);
workerPort.postMessage('SUCCESS');
}
};
// 主线程调用
const dbWorker = new worker.ThreadWorker('workers/db_worker.js');
// 初始化数据库
dbWorker.postMessage({ type: 'init' });
// 执行事务
async function migrateData() {
dbWorker.postMessage({
type: 'exec',
sql: 'INSERT INTO new_table SELECT * FROM old_table',
});
}
如何选择 TaskPool 和 Worker?
- 选择 TaskPool 的情况:
- 任务执行时间 < 3秒
- 无需维护任务间状态
- 需要动态扩缩线程池(如根据CPU核心数调整)
- 任务可独立并行(如图片处理、数学计算)
- 选择 Worker 的情况:
- 任务执行时间 > 3秒
- 需保持线程内状态(如WebSocket连接、数据库句柄)
- 需要持续双向通信(如实时数据传输)
- 任务复杂度高(如机器学习模型推理)
性能优化建议
- TaskPool 最佳实践:
- 避免在任务函数中引用外部变量(参数需可序列化)
- 单个任务函数代码控制在 50 行以内
- 使用
@Concurrent
装饰器标记并发函数
- Worker 最佳实践:
- 减少主线程与 Worker 的频繁通信
- 使用
ArrayBuffer
传递二进制数据(避免序列化开销) - 及时调用
terminate()
释放闲置 Worker