Harmonyos多线程之Worker基本使用

devtools/2024/12/22 23:07:44/

Harmonyos多线程之Worker基本使用

  • Worker的注意事项
    • 创建Worker的注意事项
      • 手动创建Worker线程
      • 自动创建Worker现成
    • 跨har包加载Worker
    • 多级Worker的声明周期管理
  • Worker和宿主线程的通信

Worker主要作用是为应用程序提供一个多线程的运行环境,可满足应用程序在执行过程中与宿主线程分离,在后台线程中运行一个脚本进行耗时操作,极大避免类似于计算密集型或高延迟的任务阻塞宿主线程的运行。具体接口信息及使用方法详情请见Worker

Worker的注意事项

  • Worker创建后需要手动管理生命周期,且最多同时运行的Worker子线程数量为64个。
    • Worker的创建和销毁耗费性能,建议开发者合理管理已创建的Worker并重复使用。Worker空闲时也会一直运行,因此当不需要Worker时,可以调用terminate()接口或close()方法主动销毁Worker。若Worker处于已销毁或正在销毁等非运行状态时,调用其功能接口,会抛出相应的错误。
    • Worker的数量由内存管理策略决定,设定的内存阈值为1.5GB和设备物理内存的60%中的较小者。在内存允许的情况下,系统最多可以同时运行64个Worker。如果尝试创建的Worker数量超出这一上限,系统将抛出错误:“Worker initialization failure, the number of workers exceeds the maximum.”。实际运行的Worker数量会根据当前内存使用情况动态调整。一旦所有Worker和主线程的累积内存占用超过了设定的阈值,系统将触发内存溢出(OOM)错误,导致应用程序崩溃。
  • 由于不同线程中上下文对象是不同的,因此Worker线程只能使用线程安全的库,例如UI相关的非线程安全库不能使用。
  • 序列化传输的数据量大小限制为16MB
  • 使用Worker模块时,需要在宿主线程中注册onerror接口,否则当Worker线程出现异常时会发生jscrash问题。
  • 不支持跨HAP使用Worker线程文件
  • 不支持在Worker工作线程中使用AppStorage

创建Worker的注意事项

Worker线程文件需要放在"{moduleName}/src/main/ets/"目录层级之下,否则不会被打包到应用中。有手动和自动两种创建Worker线程目录及文件的方式。

手动创建Worker线程

开发者需要手动创建相关目录及文件, 此时需要配置build-profile.json5的相关字段信息,Worker线程文件才能确保被打包到应用中

在当前使用Worker线程的模块下面的对应文件目录中创建一个worker线程文件, 并增加相关配置项
在这里插入图片描述

手动创建Worker需要实现代码:

import worker, { ErrorEvent, MessageEvents, ThreadWorkerGlobalScope } from '@ohos.worker'
import { JSON } from '@kit.ArkTS'// 创建woker线程中和宿主线程通信的对象
const workerPort: ThreadWorkerGlobalScope = worker.workerPort//woker线程接受主线程的消息
workerPort.onmessage = (e: MessageEvents) => {// 现成通信的具体逻辑console.log("onmessage=22222================" + JSON.stringify(e.data))// woker线程像宿主线程发送消息workerPort.postMessage("woker线程发送消息")
}// 回调函数。表示当Worker对象接收到一条无法被序列化的消息时被调用的事件处理程序,
// 处理程序在宿主线程中执行。其中回调函数中event类型为MessageEvents,表示收到的Worker消息数据。
workerPort.onmessageerror = (ev: MessageEvents) => {console.log('onmessageerror=================' + JSON.stringify(ev.data))
}// worker线程发生error错误的回调
workerPort.onerror = (err: ErrorEvent) => {console.log("worker.ets onerror" + err.message);
}

自动创建Worker现成

DevEco Studio支持一键生成Worker,在对应的{moduleName}目录下任意位置,点击鼠标右键 > New > Worker,即可自动生成Worker的模板文件及配置信息,无需再手动在build-profile.json5中进行相关配置。
在这里插入图片描述
当我们使用工具进行自动创建时, 我们可以看到配置文件中自动增加了,工具创建的AutoWorker线程类:
在这里插入图片描述

使用自动创建的方式,系统自动实现的代码:

import { ErrorEvent, MessageEvents, ThreadWorkerGlobalScope, worker } from '@kit.ArkTS';const workerPort: ThreadWorkerGlobalScope = worker.workerPort;/*** Defines the event handler to be called when the worker thread receives a message sent by the host thread.* The event handler is executed in the worker thread.** @param e message data*/
workerPort.onmessage = (e: MessageEvents) => {
}/*** Defines the event handler to be called when the worker receives a message that cannot be deserialized.* The event handler is executed in the worker thread.** @param e message data*/
workerPort.onmessageerror = (e: MessageEvents) => {
}/*** Defines the event handler to be called when an exception occurs during worker execution.* The event handler is executed in the worker thread.** @param e error message*/
workerPort.onerror = (e: ErrorEvent) => {
}

跨har包加载Worker

跨har的worker线程:
在这里插入图片描述

在entry模块中使用workerhar模块中创建的worker线程:

//宿主线程中创建woker线程const workerInstance = new worker.ThreadWorker("@workerhar/ets/workers/Worker.ets")//宿主线程像woker线程发送消息workerInstance.postMessage("宿主线程像夸har包的woker线程传递消息========")//宿主线程接受woker线程信息workerInstance.onmessage = (e: MessageEvents) => {console.log('onmessage=接受到夸har包的worker线程消息====================' + JSON.stringify(e.data))//销毁Worker对象workerInstance.terminate()}// 在调用terminate后,执行onexitworkerInstance.onexit = (code) => {console.log("main thread terminate");}workerInstance.onerror = (err: ErrorEvent) => {console.log("main error message " + err.message);}

输出结果:
在这里插入图片描述

注意: 主要区别是在与worker文件的导入路径

多级Worker的声明周期管理

由于支持创建多级Worker(即通过父Worker创建子Worker的机制形成层级线程关系),且Worker线程生命周期由用户自行管理,因此需要注意多级Worker生命周期的正确管理。若用户销毁父Worker时未能结束其子Worker的运行,会产生不可预期的结果。建议用户确保子Worker的生命周期始终在父Worker生命周期范围内,并在销毁父Worker前先销毁所有子Worker。

示例:

主线程核心代码:

// 在主线程创建worker线程(父worker),在worker线程中在次创建worker线程(子线程)const parentworker = new worker.ThreadWorker('../workers//ParentWorker')parentworker.onmessage = (e: MessageEvents) => {console.log('主线程收到父worker线程信息========================' + e.data)}parentworker.onexit = () => {console.log("父worker退出=============================")}parentworker.onerror = (error: ErrorEvent) => {console.log('主线程收到父worker的报错=======================' + error)}parentworker.postMessage('主线程发送消息给父worker')})

parentworker.ets的核心代码

workerPort.onmessage = (e: MessageEvents) => {if (e.data === "主线程发送消息给父worker") {// 创建一个子workerlet childworker = new worker.ThreadWorker("../workers/ChilderWorker");childworker.onmessage = (e: MessageEvents) => {console.log("父Worker收到子Worker的信息================" + e.data);if (e.data === '子Worker向父Worker发送信息') {workerPort.postMessage("父Worker向主线程发送信息");}}childworker.onexit = () => {console.log('子Worker退出=================')workerPort.close()}childworker.onerror = (err: ErrorEvent) => {console.log("子Worker发生报错 " + err);}childworker.postMessage("父Worker向子Worker发送信息");}
}

childerworker.ets核心代码:

workerPort.onmessage = (e: MessageEvents) => {if (e.data === "主线程发送消息给父worker") {// 创建一个子workerlet childworker = new worker.ThreadWorker("../workers/ChilderWorker");childworker.onmessage = (e: MessageEvents) => {console.log("父Worker收到子Worker的信息================" + e.data);if (e.data === '子Worker向父Worker发送信息') {workerPort.postMessage("父Worker向主线程发送信息");}}childworker.onexit = () => {console.log('子Worker退出=================')workerPort.close()}childworker.onerror = (err: ErrorEvent) => {console.log("子Worker发生报错 " + err);}childworker.postMessage("父Worker向子Worker发送信息");}
}

Worker和宿主线程的通信

worker的代码是上面的手动创建worker示例的代码.

示例代码:

//宿主线程中创建woker线程const workerInstance = new worker.ThreadWorker("../manualcreate/manualWorker")//宿主线程像woker线程发送消息workerInstance.postMessage("宿主线程像woker线程传递消息========")//宿主线程接受woker线程信息workerInstance.onmessage = (e: MessageEvents) => {console.log('onmessage=1111====================' + JSON.stringify(e.data))//销毁Worker对象workerInstance.terminate()}// 在调用terminate后,执行onexitworkerInstance.onexit = (code) => {console.log("main thread terminate");}workerInstance.onerror = (err: ErrorEvent) => {console.log("main error message " + err.message);}

输出结果:
在这里插入图片描述


http://www.ppmy.cn/devtools/144504.html

相关文章

HTML基本标签详解

HTML基本标签详解 HTML&#xff08;超文本标记语言&#xff09;是构建网页的基础&#xff0c;以下是一些常用的 HTML 基本标签及其详细说明&#xff1a; <html> 定义&#xff1a;整个 HTML 文档的根元素。示例&#xff1a;<html lang"zh"><head> …

Scala快速入门+示例

目录 定义和描述idea基础关键字变量、常量输出数据类型类型转换 函数式编程函数和方法的区别定义示例有参带返回值有参没有返回值 注意点 面向对象object和class的区别对象的属性 快速上手使用版 定义和描述 基于JVM的语言&#xff0c;支持面向对象、面向函数&#xff0c;支持…

Emacs折腾日记(四)——elisp控制结构

目前我们接着学习elisp相关语法&#xff0c;这里我是按照 elisp 简明教程 来进行学习。与其说这是我自己写得教程到不如说是在这个上面做得注释。目前我不知道这样是否侵犯相关的知识产权。目前就先这样继续学习&#xff0c;继续写记录吧。 闲话少说&#xff0c;进入本篇的正题…

【论文阅读】从单张图像到高质量3D模型的快速生成方法

导言 现有的单视角图像生成3D方法存在计算成本高、生成质量不足且缺乏多视角一致性等问题。本文介绍的方法提出了一种新框架&#xff0c;结合多视角2D深度图和RGB图像&#xff0c;通过Stable Diffusion模型生成显式表面几何和纹理。论文强调了深度图在捕捉几何信息方面的优势&…

分布式专题(6)之MongoDB复制(副本)集实战及其原理分析

一、MongoDB复制集结构 在生产环境中&#xff0c;不建议使用单机版的MongoDB服务器。原因如下&#xff1a; 单机版的MongoDB无法保证可靠性&#xff0c;一旦进程发生故障或是服务器宕机&#xff0c;业务将直接不可用。一旦服务器上的磁盘损坏&#xff0c;数据会直接丢失&#x…

QP:Query类目

Query类目 Query类目指的是根据查询内容将查询词Query归类到某个特定的分类体系中。这个体系通常是多级的&#xff0c;能够将查询词从更广泛的类别逐渐细分到更具体的子类目&#xff0c;这个体系通常在电商搜索和推荐领域中有重要的作用。 Query和Doc一般共用一套类目体系&am…

mac uniapp 转为微信小程序开发

mac uniapp 转为微信小程序开发 1.进入微信公众平台获取小程序Appid在manifest.json配置 2.打开微信开发者工具进入设置—安全设置 3.勾选服务端口 4.点击运行至微信开发工具可自动打开

C语言---数据结构---堆

要想了解堆结构&#xff0c;首先要知道什么是堆、堆是用来做什么的。 那么什么是堆呢&#xff1f; 如果有一个关键码的集合K&#xff0c;K中包含n个数据&#xff0c;将这些元素按照完全二叉树的顺序存储方式存储在一个一维数组中&#xff0c;并满足第i个数据小于等于第2*i1个…