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);}
输出结果: