HarmonyOS: 创建线程的3种方式

171 阅读4分钟

使用Worker创建线程

  • 基本概念:Worker主要为应用程序提供多线程运行环境,可让应用程序在执行过程中与宿主线程分离,在后台线程中运行脚本进行耗时操作,避免计算密集型或高延迟任务阻塞宿主线程。
  • 使用方法
    • 创建Worker线程文件:Worker线程文件需要放在{moduleName}/src/main/ets/目录层级之下。可以手动创建相关目录及文件,并配置build-profile.json5的相关字段信息;也可以使用DevEco Studio一键生成Worker,自动生成模板文件及配置信息。
    • 构造Worker实例:根据不同的API版本和模型,使用相应的构造函数传入Worker线程文件的路径来创建worker.ThreadWorkerworker.Worker实例。例如,在API 9及之后版本的Stage模型下,如果worker线程文件所在路径为"entry/src/main/ets/workers/worker.ets",则可以这样创建:const workerStage1: worker.ThreadWorker = new worker.ThreadWorker('entry/ets/workers/worker.ets');
    • 通信与任务执行:在宿主线程和Worker子线程中通过onmessagepostMessage方法进行消息传递,以实现数据交互和任务执行。
  • 注意事项
    • 需要手动管理Worker的生命周期,且最多同时运行的Worker子线程数量为64个。当不需要Worker时,应调用terminate()接口或close()方法主动销毁Worker,避免资源浪费。
    • 使用Worker模块时,需要在宿主线程中注册onerror接口,否则当Worker线程出现异常时会发生jscrash问题。
    • 不支持跨HAP使用Worker线程文件,引用HAR/HSP前,需要先配置对HAR/HSP的依赖。

使用TaskPool创建线程

  • 基本概念:TaskPool为应用程序提供多线程运行环境,能降低资源消耗、提升系统性能,开发者无需关心线程实例的生命周期。它支持在宿主线程封装任务并抛给任务队列,系统会选择合适的工作线程进行任务分发与执行,并将结果返回给宿主线程。
  • 使用方法
    • 定义任务函数:使用@Concurrent装饰器标注要在任务池中执行的函数。该装饰器从API version 9开始支持,仅在Stage模型的工程中的.ets文件中使用。被装饰的函数可以是async函数或普通函数,但禁止是generator、箭头函数、类方法,也不支持类成员函数或者匿名函数。函数内允许使用local变量、入参和通过import引入的变量,禁止使用闭包变量。
    • 创建任务并执行:在需要执行并发任务的地方,创建taskpool.Task对象,将定义好的任务函数作为参数传入,并通过taskpool.execute方法执行任务。例如:
import { taskpool } from '@kit.ArkTS';

@Concurrent
function add(num1: number, num2: number): number {
    return num1 + num2;
}

async function ConcurrentFunc(): Promise<void> {
    try {
        let task: taskpool.Task = new taskpool.Task(add, 1, 2);
        console.info("taskpool res is: " + await taskpool.execute(task));
    } catch (e) {
        console.error("taskpool execute error is: " + e);
    }
}

@Entry
@Component
struct Index {
    @State message: string = 'Hello World';

    build() {
        Row() {
            Column() {
                Text(this.message)
                   .fontSize(50)
                   .fontWeight(FontWeight.Bold)
                   .onClick(() => {
                        ConcurrentFunc();
                    })
            }
           .width('100%')
        }
       .height('100%')
    }
}
  • 注意事项
    • 任务函数在TaskPool工作线程的执行耗时不能超过3分钟(不包含Promiseasync/await异步调用的耗时,例如网络下载、文件读写等I/O任务的耗时),否则会被强制退出。
    • 实现任务的函数入参需满足序列化支持的类型。ArrayBuffer参数在TaskPool中默认转移,需要设置转移列表的话可通过接口setTransferList()设置。
    • 从API version 11开始,跨并发实例传递带方法的实例对象时,该类必须使用@Sendable装饰器标注,且仅支持在.ets文件中使用。

通过NAPI机制在C代码中使用标准线程API创建线程

  • 基本概念:通过NAPI(Native API)机制,可以在C代码中使用标准的线程API来创建线程,直接利用操作系统提供的线程创建和管理功能,实现更底层的线程控制。
  • 使用方法:通常使用pthread_create函数来创建线程,其函数原型为int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);。例如:
#include <pthread.h>

// 线程执行的函数
void *CreateArkRuntimeFunc(void *arg) {
    // 线程执行的代码逻辑
    return NULL;
}

int main() {
    pthread_t tid;
    // 创建线程
    pthread_create(&tid, nullptr, CreateArkRuntimeFunc, nullptr);
    // 其他代码逻辑
    // 等待线程结束等操作
    pthread_join(tid, NULL);
    return 0;
}