HarmonyOS CPU与I/O密集型任务开发指导
一、CPU密集型任务开发指导
CPU密集型任务是指需要占用系统资源处理大量计算能力的任务,需要长时间运行,这段时间会阻塞线程其它事件的处理,不适宜放在主线程进行。例如图像处理、视频编码、数据分析等。
基于多线程并发机制处理CPU密集型任务可以提高CPU利用率,提升应用程序响应速度。
当进行一系列同步任务时,推荐使用Worker;而进行大量或调度点较为分散的独立任务时,不方便使用8个Worker去做负载管理,推荐采用TaskPool。接下来将以图像直方图处理以及后台长时间的模型预测任务分别进行举例。
使用TaskPool进行图像直方图处理
1. 实现图像处理的业务逻辑。
2. 数据分段,将各段数据通过不同任务的执行完成图像处理。
创建Task,通过execute()执行任务,在当前任务结束后,会将直方图处理结果同时返回。
3. 结果数组汇总处理。
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%') } }
使用Worker进行长时间数据分析
本文通过某地区提供的房价数据训练一个简易的房价预测模型,该模型支持通过输入房屋面积和房间数量去预测该区域的房价,模型需要长时间运行,房价预测需要使用前面的模型运行结果,因此需要使用Worker。
1. DevEco Studio提供了Worker创建的模板,新建一个Worker线程,例如命名为“MyWorker”。
2. 在主线程中通过调用ThreadWorker的constructor()方法创建Worker对象,当前线程为宿主线程。
import worker from '@ohos.worker'; const workerInstance = new worker.ThreadWorker('entry/ets/workers/MyWorker.ts');
3. 在宿主线程中通过调用onmessage()方法接收Worker线程发送过来的消息,并通过调用postMessage()方法向Worker线程发送消息。
例如向Worker线程发送训练和预测的消息,同时接收Worker线程发送回来的消息。
// 接收Worker子线程的结果 workerInstance.onmessage = function(e) { // data:主线程发送的信息 let data = e.data; console.info('MyWorker.ts onmessage'); // 在Worker线程中进行耗时操作 } workerInstance.onerror = function (d) { // 接收Worker子线程的错误信息 } // 向Worker子线程发送训练消息 workerInstance.postMessage({ 'type': 0 }); // 向Worker子线程发送预测消息 workerInstance.postMessage({ 'type': 1, 'value': [90, 5] });
4. 在MyWorker.ts文件中绑定Worker对象,当前线程为Worker线程。
import worker, { ThreadWorkerGlobalScope, MessageEvents, ErrorEvent } from '@ohos.worker'; let workerPort: ThreadWorkerGlobalScope = worker.workerPort;
5. 在Worker线程中通过调用onmessage()方法接收宿主线程发送的消息内容,并通过调用postMessage()方法向宿主线程发送消息。
如在Worker线程中定义预测模型及其训练过程,同时与主线程进行信息交互。
import worker, { ThreadWorkerGlobalScope, MessageEvents, ErrorEvent } from '@ohos.worker'; let workerPort: ThreadWorkerGlobalScope = worker.workerPort; // 定义训练模型及结果 let result; // 定义预测函数 function predict(x) { return result[x]; } // 定义优化器训练过程 function optimize() { result = {}; } // Worker线程的onmessage逻辑 workerPort.onmessage = function (e: MessageEvents) { let data = e.data // 根据传输的数据的type选择进行操作 switch (data.type) { case 0: // 进行训练 optimize(); // 训练之后发送主线程训练成功的消息 workerPort.postMessage({ type: 'message', value: 'train success.' }); break; case 1: // 执行预测 const output = predict(data.value); // 发送主线程预测的结果 workerPort.postMessage({ type: 'predict', value: output }); break; default: workerPort.postMessage({ type: 'message', value: 'send message is invalid' }); break; } }
6. 在Worker线程中完成任务之后,执行Worker线程销毁操作。销毁线程的方式主要有两种:根据需要可以在宿主线程中对Worker线程进行销毁;也可以在Worker线程中主动销毁Worker线程。
在宿主线程中通过调用onexit()方法定义Worker线程销毁后的处理逻辑。
// Worker线程销毁后,执行onexit回调方法 workerInstance.onexit = function() { console.info("main thread terminate"); }
方式一:在宿主线程中通过调用terminate()方法销毁Worker线程,并终止Worker接收消息。
// 销毁Worker线程 workerInstance.terminate();
方式二:在Worker线程中通过调用close()方法主动销毁Worker线程,并终止Worker接收消息。
// 销毁线程 workerPort.close();
二、 I/O密集型任务开发指导
使用异步并发可以解决单次I/O任务阻塞的问题,但是如果遇到I/O密集型任务,同样会阻塞线程中其它任务的执行,这时需要使用多线程并发能力来进行解决。
I/O密集型任务的性能重点通常不在于CPU的处理能力,而在于I/O操作的速度和效率。这种任务通常需要频繁地进行磁盘读写、网络通信等操作。此处以频繁读写系统文件来模拟I/O密集型并发任务的处理。
1. 定义并发函数,内部密集调用I/O能力。
import fs from '@ohos.file.fs'; // 定义并发函数,内部密集调用I/O能力 @Concurrent async function concurrentTest(fileList: string[]) { // 写入文件的实现 async function write(data, filePath) { let file = await fs.open(filePath, fs.OpenMode.READ_WRITE); await fs.write(file.fd, data); fs.close(file); } // 循环写文件操作 for (let i = 0; i < fileList.length; i++) { write('Hello World!', fileList[i]).then(() => { console.info(`Succeeded in writing the file. FileList: ${fileList[i]}`); }).catch((err) => { console.error(`Failed to write the file. Code is ${err.code}, message is ${err.message}`) return false; }) } return true; }
2. 使用TaskPool执行包含密集I/O的并发函数:通过调用execute()方法执行任务,并在回调中进行调度结果处理。示例中的filePath1和filePath2的获取方式请参见获取应用文件路径。
import taskpool from '@ohos.taskpool'; let filePath1 = ...; // 应用文件路径 let filePath2 = ...; // 使用TaskPool执行包含密集I/O的并发函数 // 数组较大时,I/O密集型任务任务分发也会抢占主线程,需要使用多线程能力 taskpool.execute(concurrentTest, [filePath1, filePath2]).then((ret) => { // 调度结果处理 console.info(`The result: ${ret}`); })
本文由博客一文多发平台 OpenWrite 发布!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
OpenHarmony自定义构建函数:@Builder装饰器
前面章节介绍了如何创建一个自定义组件。该自定义组件内部UI结构固定,仅与使用方进行数据传递。ArkUI还提供了一种更轻量的UI元素复用机制@Builder,@Builder所装饰的函数遵循build()函数语法规则,开发者可以将重复使用的UI元素抽象成一个方法,在build方法里调用。 为了简化语言,我们将@Builder装饰的函数也称为“自定义构建函数”。 说明: 从API version 9开始,该装饰器支持在ArkTS卡片中使用。 装饰器使用说明 自定义组件内自定义构建函数 定义的语法: @Builder MyBuilderFunction() { ... } 使用方法: this.MyBuilderFunction() { ... } ● 允许在自定义组件内定义一个或多个自定义构建函数,该函数被认为是该组件的私有、特殊类型的成员函数。 ● 自定义构建函数可以在所属组件的build方法和其他自定义构建函数中调用,但不允许在组件外调用。 ● 在自定义函数体中,this指代当前所属组件,组件的状态变量可以在自定义构建函数内访问。建议通过this访问自定义组件的状态变量而不...
- 下一篇
MakuGenerator 3.0.3 发布:Spring Boot 3.0 代码生成器
介绍 maku-generator 是一款低代码生成器,可根据自定义模板内容,快速生成代码,可实现项目的快速开发、上线,减少重复的代码编写,开发人员只需专注业务逻辑即可。采用 MIT 开源协议,完全免费开源,可免费用于商业项目等场景。 仓库地址:https://gitee.com/makunet/maku-generator 开发文档:https://maku.net/docs/maku-generator 演示环境:https://demo.maku.net/maku-generator 官网地址:https://maku.net 更新日志 优化SpringBoot3.0+版本配置,废弃spring.factories 优化租户场景,禁用租户模式 导入表时,默认将表名作为功能名 实体类字段转驼峰时,数据库字段大写时可能出现异常显示 前端在对密码传输和接收的时候,也进行加密和解密 后端请求支持对参数进行AES加密解密 升级springboot 到 3.1.4 升级element-plus 到 2.3.4 项目特点 友好的代码结构及注释,便于阅读及二次开发 支持 spring boot ...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- 2048小游戏-低调大师作品
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- SpringBoot2全家桶,快速入门学习开发网站教程
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS6,CentOS7官方镜像安装Oracle11G