当前位置: 首页 > 科技观察

OpenHarmonyStageWorker多线程

时间:2023-03-12 00:22:25 科技观察

了解更多开源请访问:开源基础软件社区https://ost.51cto.comOpenHarmony有一个并行线程与主线程-Worker的独立线程。它在不阻塞主线程的情况下处理耗时操作起到了重要作用,多线程并发可以提高CPU和内存利用率。在实际开发项目中,经常会遇到网络请求、文件读写、大图片加载等比较耗时的操作。如果这些耗时的操作都在主线程中处理,应用程序的UI界面就会卡住,无法操作。但是需要注意的是,在Worker线程中不能直接操作UI,需要通过消息通知UI线程进行更新。社区介绍:Worker开发环境系统:OpenHarmony3.2beta4开发板:DAYU200SDK:API9-FullSDK(3.2.9.2)效果视频地址开发调试社区提供WorkerDemo,使用API??8,FA模型,有兴趣的可以参考:JsWorker。API9版本之后,只能使用Stage模型进行开发。下面我们介绍基于API9和Stage模型的Worker异步线程的开发。需求首先我们来确认一下我们开发调试的内容1.UI界面显示一行显示运行过程的文字,以及三个按钮:主线程保存数据,子线程保存数据,UI。主线程保存数据:UI线程向指定文件写入1,000,000条数据。子线程保存数据:通知Worker线程向指定文件写入1,000,000条数据。UI:界面toast提示“点击UI”,用于测试不同线程保存数据是否会阻塞主线程操作。2.在主线程中向指定文件写入数据。写入完成后,Toast会提示:“数据保存成功”。3、在子线程中向指定文件写入数据。写入完成后,Toast会提示:“数据保存成功”。4.执行2和3时,点击UI按钮可以查看运行结果。涉及到的API@ohos.worker@ohos.file.fs暂时还没有,大家可以参考:@ohos.fileio@ohos.promptAction项目结构在介绍相关代码之前,先来看看API9阶段模型项目目录结构:创建Worker子线程的关键代码需要构造一个ThreadWorker实例,通过ThreadWorker实例属性onmessage监听Worker向宿主线程发送的消息。1、ThreadWorker参数:参数名类型必填。scriptURLstring是Worker执行脚本的路径。
在FA和Stage模型下,DevEcoStudio会在以下两种情况下新建Worker项目路径:
(a)worker脚本所在目录与pages目录在同一层级。
(b)worker脚本所在目录与pages目录不在同一层级。optionsWorkerOptions没有Worker构建的选项。返回值:类型说明ThreadWorker执行ThreadWorker构造函数生成的ThreadWorker对象,失败则返回undefined。代码:来自“@ohos.worker”的index.etsimportworker;privateworkerInstance:worker.ThreadWorkerprivatereadonlyscriptURL:string='entry/ets/worker/worker.ts'aboutToAppear(){//在主线程中创建一个Worker对象this.workerInstance=newworker.ThreadWorker(this.scriptURL,{name:'worker_thread'})//注册监听器//具体宿主线程发送的信息this.workerInstance.onmessage=function(e){letdata=e.dataconsole.info(`${TAG}workerInstance.onmessage${data}`)this.result=datathis.showSaveToast()}.bind(this)this.workerInstance.onexit=function(){console.info(`${TAG}workerInstanceonexit`)}}showSaveToast(){//数据保存成功promptAction.showToast({message:'Datasavedsuccessfully',duration:2000})}(1)这里我们需要了解worker.ThreadWorker接口Stage模型中的参数scriptURL="entry/ets/worker/worker.ts":entry:是module.json5文件中模块的name属性对应的值;ets:表示当前使用的语言。(2)主线程和Worker线程之间支持的数据类型,参考SerializationSupportTypes。2、worker/worker.tsworker.ts脚本通过@ohos.worker.workerPort获取ThreadWorkerGlobalScope对象,主要用于Worker线程与宿主线程的通信,可以通过postMessage向宿主线程发送消息界面。onMessage:表示当Worker线程通过postMessage接口从其宿主线程接收到消息时调用的事件处理器,该处理器在Worker线程中执行;onMessageerror:表示当Worker对象收到无法反序列化的消息时调用的事件处理器,该处理器在Worker线程中执行。worker.ts代码从“@ohos.worker”导入工人;import{MyMessage}from'../modele/MyMessage'import{MessageType}from'../modele/MessageType'importfileIofrom'@ohos.file.fs'constTAG:string='[worker]'//创建工作线程中与主线程通信的对象constworkerPort=worker.workerPortletfd:number=0//工作线程从主线程接收信息workerPort.onmessage=function(e){//data:发送的消息通过主线程letdata=e.dataasMyMessageconsole.info(`${TAG}workerPort.onmessage${e}`)lettype=data.typeswitch(type){caseMessageType.CLOSE:{//关闭线程console.info(`${TAG}workerPort.onmessageclose`)workerPort.close()break}caseMessageType.SAVE:{console.info(`${TAG}workerPort.onmessage保存路径:${data.path}}`)if(data.path){//保存数据到文件if(fd<=0){fd=fileIo.openSync(data.path,0o2|0o100).fd}for(varindex=0;index<1000000;index++){fileIo.writeSync(fd,'WorkerThread'+data.data+''+index+'\n')}}//发送消息到主线程workerPort.postMessage(data.data+'datasavingcompleted')break}default:{console.error(`${TAG}workerPort.onmessagemessagetypeerror`)}}}//工作线程错误回调workerPort.onerror=function(e){console.info(`${TAG}workerPort.onerror${JSON.stringify(e)}`)}3.更新UI界面,通过worker.workerPort.postMessage()向宿主线程发送消息。宿主线程的worker.ThreadWorker().onMessage()toast收到消息后提示:“数据保存成功”更新UI。这里的代码体现在上面的1,ThreadWorker和2,worker/worker.ts。4.添加配置在项目的模块级build-profile.json文件的buildOption属性中添加配置信息。"buildOption":{"sourceOption":{"workers":["./src/main/ets/worker/worker.ts"]}}5、interfacebuild(){Column(){Text(this.result).fontSize(18).fontWeight(FontWeight.Bold)Button('保留主线数').width('50%').height(50).fontSize(24).margin({top:20,bottom:20}).onClick(()=>{this.showStartSaveToast()this.result='workertest..'letfd=fileIo.openSync(globalThis.getContext(this).filesDir+'/'+'catch_log.txt',0o2|0o100).fdfor(varindex=0;index<1000000;index++){fileIo.writeSync(fd,'UIThreadThiswritedata'+index+'\n')}this.result='worker测试成功'this.showSaveToast()})Button('保存行数').width('50%').height(50).fontSize(24).margin({top:20,bottom:20}).onClick(()=>{this.showStartSaveToast()this.result='workertest..'letoldData='Thiswritedata'letsendData:MyMessage=newMyMessage()sendData.type=MessageType.SAVEsendData.path=globalThis.getContext(this).filesDir+'/'+'catch_log.txt'sendData.data=oldDatathis.sendMessage(sendData)})Button('UI').width('50%').height(50).fontSize(24).margin({top:20,bottom:20}).onClick(()=>{promptAction.showToast({message:'clickUI',duration:3000})})}.width('100%').height('100%')}这里完成的Worker子线程处理耗时操作任务