一、背景
在鸿蒙开发中,提供了TaskPool与Worker两种多线程并发方案,两种方案在效果与使用上存在差异
二、两者区别
2.1、使用场景
对比项 | TaskPool(任务池) | Worker(工作线程) |
任务类型 | 计算密集型、短时任务 | I/O密集型、长时任务 |
执行时长 | 短时间任务(毫秒到秒级) | 长时间运行(秒到持续运行) |
使用频率 | 高频率触发 | 低频率创建 |
资源消耗 | 线程复用,资源消耗低 | 独立线程,资源消耗较高 |
典型应用 | 1. 图片处理 2. 数据计算 3. 批量数据处理 4. 并行算法 | 1. SSE/WebSocket长连接 2. 文件下载/上传 3. 音视频处理 4. 后台服务 |
场景示例 | taskpool.execute(processImage) | new worker.ThreadWorker('sse.worker') |
2.2、生命周期
| 对比项 | TaskPool(任务池) | Worker(工作线程) |
|---|---|---|
| 创建时机 | 任务提交时自动分配线程 | 显式创建:new worker.ThreadWorker() |
| 销毁时机 | 任务执行完自动释放 | 显式销毁:worker.terminate() |
| 生命周期 | 与单次任务绑定 | 与Worker实例绑定 |
| 内存管理 | 自动回收,无需手动管理 | 需手动管理,避免内存泄漏 |
| 恢复能力 | 任务失败需重新提交 | Worker崩溃需重新创建 |
| 持久化 | 不支持持久化运行 | 支持长时间持续运行 |
| 配置要求 | 无需额外配置 | 需在build-profile.json5中配置 |
2.3、性能特性对比
| 对比项 | TaskPool(任务池) | Worker(工作线程) |
|---|---|---|
| 启动开销 | 小(线程复用) | 大(创建新线程) |
| 内存占用 | 低(共享线程资源) | 高(独立内存空间) |
| 执行效率 | 高(适合批量小任务) | 中等(适合长任务) |
| 通信开销 | 一次序列化/反序列化 | 多次消息传递开销 |
| 资源竞争 | 可能(共享线程池) | 无(独立资源) |
2.4、数据传输方式
| 对比项 | TaskPool(任务池) | Worker(工作线程) |
|---|---|---|
| 通信机制 | 函数参数和返回值 | postMessage/onmessage消息机制 |
| 数据传递 | 参数和返回值自动序列化 | 需手动序列化消息数据 |
| 数据大小 | 适合中小型数据 | 支持较大数据量 |
| 传输性能 | 序列化/反序列化开销 | 消息传递开销 |
| 共享内存 | 不支持,完全隔离 | 支持可转移对象(零拷贝) |
| 双向通信 | 单向(任务→结果) | 双向(主线程⇌Worker线程) |
| 实时性 | 任务完成后一次性返回 | 支持实时消息交互 |
| 数据示例 | return processedData; | workerPort.postMessage(data); |
总结:
Worker处理长连接、文件操作等稳定后台任务
TaskPool处理UI触发的计算密集型短任务
三、如何识别任务选用类型
核心:怎么辨别该线程并发任务是选用taskpool还是worker
考量因素 | 倾向TaskPool | 倾向Worker |
执行时长 | 5-10秒的短任务 | > 10秒的长任务 |
执行频率 | 高频率触发(每秒多次) | 低频率触发(分钟/小时级) |
持续性 | 一次性执行,无需保持状态 | 需要持续运行,保持状态 |
实时性要求 | 需要快速返回结果 | 可以接受延迟响应 |
通信需求 | 仅需一次性结果反馈(无需中途交互,完成后返回结果) | 需要双向持续通信(实时反馈进度 / 接收主线程指令) |