此文章内容兼容API12,使用harmony next应用开发
概念解释
1,并发
并发
2,多线程并发
- 常见两种模型: 基于内存共享的并发模型,和基于消息通信的并发模型
- Actor 模型基于消息通信
- TaskPool 和 Worker 都是基于Actor 模型实现,TaskPool更是对Worker 的进一步封装
3,TaskPool 和 Worker 区别
Worker
- 线程池创建线程个数最多是64个。超过则创建失败。
- 使用Worker,传输序列化数据大小限制在16MB。
- 引用HAR/HSP前,首先要配置对HAR/HSP的依赖。不支持 跨HAP使用Worker线程文件。
- 任务执行时长上限,无限制。
- 不支持设置任务的优先级,不支持取消任务
- Worker需要自行封装参数,通过 onmessage 接收返回数据
- 生命周期:开发者自行管理Worker的数量及生命周期。
TaskPool
- TaskPool线程池的数量会根据硬件条件、任务负载等情况动态调整。
- Promise不支持跨线程传递,不能作为concurrent function的返回值。
- 任务执行时长上限,为3分钟(执行耗时不能超过3分钟)。
- 支持设置任务的优先级,支持取消任务
- TaskPool可以直接传递参数、可以直接接收返回数据;
- 生命周期:TaskPool自行管理生命周期,无需关心任务负载高低。
4,使用场景对比
- 由于TaskPool的工作线程会绑定系统的调度优先级,并且支持负载均衡(自动扩缩容),而Worker需要开发者自行创建,存在创建耗时以及不支持设置调度优先级,故在性能方面使用TaskPool会优于Worker,因此大多数场景推荐使用TaskPool。
- 运行时间超过3分钟(不包含Promise和async/await异步调用的耗时,例如网络下载、文件读写等I/O任务的耗时)的任务。例如后台进行1小时的预测算法训练等CPU密集型任务,需要使用Worker。
使用详解 - TaskPool
//[函数,参数]
function execute(func: Function, ...args: Object[]): Promise<Object>;
//[任务,优先级]
function execute(task: Task, priority?: Priority): Promise<Object>;
//[任务组,优先级]
function execute(group: TaskGroup, priority?: Priority): Promise<Object[]>;
1,使用示例
//[函数,参数]
fn1 = async () => {
// 执行任务
const res = await taskpool.execute(func1, this.num)
this.num = Number(res)
}
@Concurrent
function func1(n: number) {
return 1 + n
}
-------
//[任务,优先级]
fn1 = async () => {
// 同时创建和执行10个任务 指定第10个任务是最高优先级
for (let index = 1; index <= 10; index++) {
const task = new taskpool.Task(func1, index)
if (index !== 10) {
taskpool.execute(task, taskpool.Priority.LOW)
} else {
taskpool.execute(task, taskpool.Priority.HIGH)
}
}
}
------
//[任务组,优先级]
fn1 = async () => {
// 创建任务组
const taskGroup = new taskpool.TaskGroup()
for (let index = 1; index <= 10; index++) {
const task = new taskpool.Task(func1, index)
taskGroup.addTask(task)
}
// 执行任务组
const res = await taskpool.execute(taskGroup)
}
2,注意事项
- 函数必须使用 @Concurrent 装饰
- 函数需要function关键字;
- 函数需要声明在@Component外
- 函数如果调用了外部某类方法或类实例方法,某类需要使用装饰器@Sendable标注,通过import方式导入使用
- 在子线程直接getContext(),是拿不到主线程的上下文的,需要主线程手动传上下文
- 子线程不要做UI渲染操作
3,线程间通信
- 子线程中使用 sendData发送数据,主线程中使用onReceiveData接收数据
@Concurrent
function func1(n: number) {
// 假设这里是持续发送的数据
taskpool.Task.sendData((new Date).toLocaleString())
return 100
}
----
fn1 = async () => {
const task = new taskpool.Task(func1, 100)
// 主线程监听到的数据
task.onReceiveData((result: string) => {
console.log("主线程监听到的数据", result)
})
// 直接得到func1的结果
const res = await taskpool.execute(task)
console.log("直接返回的结果", res)
}