并发模型是用来实现不同应用场景中并发任务的编程模型,常见的并发模型分为基于内存共享的并发模型和基于消息通信的并发模型。
ArkTS提供了TaskPool和Worker两种并发能力供开发者选择,其具体的实现特点和各自的适用场景存在差异。TaskPool(任务池)和Worker的作用是为应用程序提供一个多线程的运行环境,用于处理耗时的计算任务或其他密集型任务。可以有效地避免这些任务阻塞主线程,从而最大化系统的利用率,降低整体资源消耗,并提高系统的整体性能。
表1 TaskPool和Worker的实现特点对比
实现 | TaskPool | Worker |
---|---|---|
内存模型 | 线程间隔离,内存不共享。 | 线程间隔离,内存不共享。 |
参数传递机制 | 采用标准的结构化克隆算法(Structured Clone)进行序列化、反序列化,完成参数传递。 支持ArrayBuffer转移和SharedArrayBuffer共享。 | 采用标准的结构化克隆算法(Structured Clone)进行序列化、反序列化,完成参数传递。 支持ArrayBuffer转移和SharedArrayBuffer共享。 |
参数传递 | 直接传递,无需封装,默认进行transfer。 | 消息对象唯一参数,需要自己封装。 |
方法调用 | 直接将方法传入调用。 | 在Worker线程中进行消息解析并调用对应方法。 |
返回值 | 异步调用后默认返回。 | 主动发送消息,需在onmessage解析赋值。 |
生命周期 | TaskPool自行管理生命周期,无需关心任务负载高低。 | 开发者自行管理Worker的数量及生命周期。 |
任务池个数上限 | 自动管理,无需配置。 | 同个进程下,最多支持同时开启8个Worker线程。 |
任务执行时长上限 | 无限制。 | 无限制。 |
设置任务的优先级 | 不支持。 | 不支持。 |
执行任务的取消 | 支持取消任务队列中等待的任务。 | 不支持。 |
TaskPool和Worker均支持多线程并发能力。TaskPool偏向独立任务维度,该任务在线程中执行,无需关注线程的生命周期;而Worker偏向线程的维度,支持长时间占据线程执行,需要主动管理线程生命周期。
常见的一些开发场景及适用具体说明如下:
taskpool,通过管理Task进行多线程的,通过taskpool.execute执行的,返回Promise对象。
Task的构造方法Task(func,args),func是执行的函数,该函数func需要用@Concurrent装饰器进行装饰,否则不会通过验证。
taskpool是可以通过taskpool.cancel结束Task任务的,也算是一种管理吧。
@Concurrent仅支持在Stage模型中使用,args是func的参数。@Concurrent装饰器不能在控件中声明。
taskpool.Task是有优先级的,执行的时候通过taskpool.Priority.HIGH标记优先级的
- @Concurrent
- function func(args) {
- console.log("func: " + args);
- return args;
- }
-
- const task: taskpool.Task = new taskpool.Task(func,"kang");
- taskpool.execute(task, taskpool.Priority.HIGH);
- taskpool.cancel(task);
执行Task后想获得其结果,可以用async/awaite获取
- @Concurrent
- function func(args) {
- console.log("func: " + args);
- return args;
- }
-
- async function taskpoolTest() {
- let task = new taskpool.Task(func, 100);
- let value = await taskpool.execute(task);
- console.log("taskpool result: " + value);
- }
-
- taskpoolTest();
CPU密集型任务是指需要占用系统资源处理大量计算能力的任务,需要长时间运行,这段时间会阻塞线程其它事件的处理,不适宜放在主线程进行。例如图像处理、视频编码、数据分析等。
基于多线程并发机制处理CPU密集型任务可以提高CPU利用率,提升应用程序响应速度。
示例:
- import taskpool from '@ohos.taskpool';
-
- @Concurrent
- function imageProcessing(dataSlice: ArrayBuffer) {
- // 步骤1: 具体的图像处理操作及其他耗时操作
- return dataSlice;
- }
-
- function histogramStatistic(pixelBuffer: ArrayBuffer) {
- // 步骤2: 分成三段并发调度
- let number = pixelBuffer.byteLength / 3;
- let buffer1 = pixelBuffer.slice(0, number);
- let buffer2 = pixelBuffer.slice(number, number * 2);
- let buffer3 = pixelBuffer.slice(number * 2);
-
- let task1 = new taskpool.Task(imageProcessing, buffer1);
- let task2 = new taskpool.Task(imageProcessing, buffer2);
- let task3 = new taskpool.Task(imageProcessing, buffer3);
-
- taskpool.execute(task1).then((ret: ArrayBuffer[]) => {
- // 步骤3: 结果处理
- });
- taskpool.execute(task2).then((ret: ArrayBuffer[]) => {
- // 步骤3: 结果处理
- });
- taskpool.execute(task3).then((ret: ArrayBuffer[]) => {
- // 步骤3: 结果处理
- });
- }
-
- @Entry
- @Component
- struct Index {
- @State message: string = 'Hello World'
-
- build() {
- Row() {
- Column() {
- Text(this.message)
- .fontSize(50)
- .fontWeight(FontWeight.Bold)
- .onClick(() => {
- let data: ArrayBuffer;
- histogramStatistic(data);
- })
- }
- .width('100%')
- }
- .height('100%')
- }
- }
今天关于并发的就先写到这,下一篇woker