【ArkTS】“一篇带你掌握TaskPool与Worker两种多线程并发方案”

246 阅读3分钟

前言

应用中的并发优化就是在响应用户操作期间,尽可能地让主线程只执行UI绘制相关的任务,而将非UI的耗时任务分配给其他线程或者延迟处理。这样借助多线程的异步技术,充分利用多核处理器的能力,提高应用程序的并发处理能力,减少用户等待时间,保证用户界面的响应流畅性。

ArkTS为我们提供了TaskPool与Worker两种多线程并发方案。

(小tips:鸿蒙是多线程噢!!)


一、TaskPool和Worker工作原理

TaskPool与Worker两种多线程并发能力均是基于 Actor并发模型实现的。 Worker主、子线程通过收发消息进行通信;TaskPool基于Worker做了更多场景化的功能封装

1.Worker工作原理

Worker主要作用是为应用程序提供一个多线程的运行环境,可满足应用程序在执行过程中与主线程分离,在后台线程中运行一个脚本进行耗时操作,极大避免类似于计算密集型或高延迟的任务阻塞主线程的运行。 工作原理如下图所示: 在这里插入图片描述 在多核的情况下(下图中的CPU 1和CPU 2同时工作),多个Worker线程(下图中的Worker thread1和Worker thread2)可以同时执行。 在这里插入图片描述

2.TaskPool工作原理

任务池(TaskPool)作用是为应用程序提供一个多线程的运行环境,降低整体资源的消耗、提高系统的整体性能,且您无需关心线程实例的生命周期。 工作原理如下图: 在这里插入图片描述

注意:两种多线程方法内存都是不共享的!

二、使用方法

1.taskPool的用法

注意事项:

  • 实现任务的函数需要使用**@Concurrent装饰器标注,且仅支持在.ets文件中使用,还必须是一个全局函数**。
  • 重点多线程绝对不允许闭包代码出现!!!!
  • taskPool的函数几乎不能使用的第三方自己编写的工具(原因如上)
  • taskPool是由操作系统调度,可以设置优先级,默认级别是中等,不需要开发者占用
  • taskPool是直接传递参数

绝对不允许的代码如下(示例):

function bar() {
}

@Concurrent
function foo() {
bar(); // 违反闭包原则,报错
}
 

taskpool使用示例:

@Concurrent
function loopMillion() {
}

使用方式一:
   taskpool.execute(loopMillion) // 开启多线程
使用方式二:
   const task1 = new taskpool.Task(loopMillion)
   taskpool.execute(task1, taskpool.Priority.HIGH)

值得一提的是,taskPool执行完成会在操作系统控制下自焚,不需要我们销毁。

2.Worker的用法

注意事项:

  • Worker创建后需要手动管理生命周期(需要开发者手动关闭),且最多同时运行的Worker子线程数量为64个。
  • workder是通过onmessage和postMessage发消息实现主线程和子线程的通信的

创建方式: 在这里插入图片描述

3.注意事项

taskPool和worker不能接受被 -State/Prop/Link 修饰的参数 假如一定想传递这种参数- let a = [...this.banners]


总结

TaskPool与Worker是性能优化的两种方式,结合我们开发需求进行选择。