鸿蒙多线程应用-taskPool
并发模型
并发模型是用来实现不同应用场景中并发任务的编程模型,常见的并发模型分为基于内存共享的并发模型和基于消息通信的并发模型。
Actor并发模型作为基于消息通信并发模型的典型代表,不需要开发者去面对锁带来的一系列复杂偶发的问题,同时并发度也相对较高,因此得到了广泛的支持和使用。
当前鸿蒙ArkTS提供了TaskPool和Worker两种并发能力,TaskPool和Worker都基于Actor并发模型实现。
内存共享并发模型指多线程同时执行任务,这些线程依赖同一内存并且都有权限访问,线程访问内存前需要抢占并锁定内存的使用权,没有抢占到内存的线程需要等待其他线程释放使用权再执行。
Actor并发模型每一个线程都是一个独立Actor,每个Actor有自己独立的内存,Actor之间通过消息传递机制触发对方Actor的行为,不同Actor之间不能直接访问对方的内存空间。Actor并发模型对比内存共享并发模型的优势在于不同线程间内存隔离,不会产生不同线程竞争同一内存资源的问题。开发者不需要考虑对内存上锁导致的一系列功能、性能问题,提升了开发效率。
由于Actor并发模型线程之间不共享内存,需要通过线程间通信机制传输并发任务和任务结果。
TaskPool简介
任务池(TaskPool)作用是为应用程序提供一个多线程的运行环境,降低整体资源的消耗、提高系统的整体性能,且您无需关心线程实例的生命周期。
TaskPool支持开发者在宿主线程封装任务抛给任务队列,系统选择合适的工作线程,进行任务的分发及执行,再将结果返回给宿主线程。接口直观易用,支持任务的执行、取消,以及指定优先级的能力,同时通过系统统一线程管理,结合动态调度及负载均衡算法,可以节约系统资源。系统默认会启动一个任务工作线程,当任务较多时会扩容,工作线程数量上限跟当前设备的物理核数相关,具体数量内部管理,保证最优的调度及执行效率,长时间没有任务分发时会缩容,减少工作线程数量。
TaskPool注意事项
-
实现任务的函数需要使用@Concurrent装饰器标注,且仅支持在.ets文件中使用。
-
从API version 11开始,跨并发实例传递带方法的实例对象时,该类必须使用装饰器@Sendable装饰器标注,且仅支持在.ets文件中使用。
-
任务函数在TaskPool工作线程的执行耗时不能超过3分钟(不包含Promise和async/await异步调用的耗时,例如网络下载、文件读写等I/O任务的耗时),否则会被强制退出。
-
实现任务的函数入参需满足序列化支持的类型,详情请参见线程间通信对象。
-
ArrayBuffer参数在TaskPool中默认转移,需要设置转移列表的话可通过接口setTransferList()设置。
-
由于不同线程中上下文对象是不同的,因此TaskPool工作线程只能使用线程安全的库,例如UI相关的非线程安全库不能使用。
-
序列化传输的数据量大小限制为16MB。
-
Priority的IDLE优先级是用来标记需要在后台运行的耗时任务(例如数据同步、备份),它的优先级别是最低的。这种优先级标记的任务只会在所有线程都空闲的情况下触发执行,并且只会占用一个线程来执行。
-
Promise不支持跨线程传递,如果TaskPool返回pending或rejected状态的Promise,会返回失败;对于fulfilled状态的Promise,TaskPool会解析返回的结果,如果结果可以跨线程传递,则返回成功。
-
不支持在TaskPool工作线程中使用AppStorage。
TaskPool应用实例
生产者消费者模型应用taskPool的具体代码实现
1.生产者
import { taskpool } from '@kit.ArkTS';
import { stingToUint8, uint8TransformString } from './utils';@Concurrent
export async function producer(ArrayBuffer: Int32Array, dataBuffer: Uint8Array, newStr: string) {let i32a = ArrayBuffer;let array = dataBufferif (array[array.length-1] !== 0) {taskpool.Task.sendData(false)let runner = new taskpool.SequenceRunner()console.log("-----atomics-producer-push-fal-" + newStr)return}let jsonStr: string = uint8TransformString(array)let arr: string[] = []try {arr= JSON.parse(jsonStr) as string[]} catch (e) {taskpool.Task.sendData(false)return}arr.push(newStr)let newArrJson = JSON.stringify(arr) ?? ''//console.log("newArrJson" + newArrJson)let isFinish = stingToUint8(newArrJson,array,4)if (!isFinish) {arr.pop()let newArrJson1 = JSON.stringify(arr) ?? ''stingToUint8(newArrJson1,array,4)taskpool.Task.sendData(false)console.log("-----atomics-producer-push-fal-" + newStr)}else{console.log("-----atomics-producer-push-sec-" + newStr)}Atomics.notify(i32a, 0, 1)Promise.resolve()
}
2.消费者
import { getStringArrayFromJson, testMethod, uint8TransformString} from './utils';
import { buffer, taskpool } from '@kit.ArkTS';
import { ThreadUtils } from './ThreadUtils';@Concurrent
export async function consumerTask(ArrayBuffer: Int32Array, dataBuffer: Uint8Array): Promise<void> {let i32a = ArrayBuffer;let array = dataBufferwhile (true) {let jsonStr: string = uint8TransformString(array)let arr = getStringArrayFromJson(jsonStr)if (arr.length == 0) {Atomics.wait(i32a, 0, 0);} else {let i = 4for (let index = 0; index < array.byteLength; index++) {if (i >= array.byteLength) {break}Atomics.store(array, i++, 0)}taskpool.Task.sendData(true)let writeResult: boolean = truewhile ((writeResult == true || writeResult == false)) {let ele = arr.shift()if (!ele) {break}writeResult = await ThreadUtils.getInstance().writeToFile(ele)console.log('-----atomics-consumer-' + ele)}}}
}
3.字符串和字节码相互转换工具
export function testMethod(str: string) {console.log('--test-function-str-' + str)
}
export function uint8TransformString(array:Uint8Array): string{let jsonStr: string = JSON.stringify([])let tempArr: number[] = []let j = 0for (let index = 0; index < array.length; index++) {if (array[index] == 0) {continue}tempArr[j++] = array[index]}let temp = new Uint8Array(tempArr)if (temp.byteLength > 0) {let str = '';for (let i = 0; i < temp.length; ) {let byte1 = temp[i];let codePoint: numberif (byte1 >> 7 === 0) { // 1字节codePoint = byte1;i += 1;} else if (byte1 >> 5 === 0b110) { // 2字节codePoint = ((byte1 & 0b11111) << 6) | (temp[i + 1] & 0b111111);i += 2;} else if (byte1 >> 4 === 0b1110) { // 3字节codePoint = ((byte1 & 0b1111) << 12) | ((temp[i + 1] & 0b111111) << 6) | (temp[i + 2] & 0b111111);i += 3;} else {// 错误处理:不支持的字节序列i += 1; // 跳过当前字节continue;}str += String.fromCodePoint(codePoint)console.info('字节流转成可理解的字符串:' + str);}jsonStr = str}return jsonStr
}
//
export function stingToUint8(json: string, array:Uint8Array,formIndex: number = 0) : boolean{let i = formIndexlet isFinish = truefor (let index = 0; index < json.length; index++) {if (i >= array.byteLength) {if (index < json.length - 1) {isFinish = false}break}const element = json.charCodeAt(index);if (element > 0x7FF) {Atomics.store(array, i++, (0xE0 | (element >> 12)))Atomics.store(array, i++, (0x80 | ((element >> 6) & 0x3F)))Atomics.store(array, i++, (0x80 | (element & 0x3F)))} else if (element > 0x7F) {Atomics.store(array, i++, (0xC0 | (element >> 6)))Atomics.store(array, i++, (0x80 | (element & 0x3F)))} else {Atomics.store(array, i++, (element))}}//剩余空间赋值0for (let index = i; index < array.length; index++) {array[index] = 0}return isFinish
}
4.单例工具
import { taskpool } from '@kit.ArkTS';
import { it } from '@ohos/hypium';
import { consumerTask } from './consumer';
import { producer } from './product';export class ThreadUtils {private tempLogList: Array<string> = new Array()private static instance: ThreadUtilsprivate sab :SharedArrayBufferprivate ui8 :Uint8Arrayprivate i32a :Int32Arrayprivate constructor(bufferSize:number = 1024) {this.sab = new SharedArrayBuffer(bufferSize)this.ui8 = new Uint8Array(this.sab)this.i32a = new Int32Array(this.sab)this.startConsumer()};writeLog(log: string) {if (this.flag) {this.tempLogList.push(log)}else {this.product(log)}}public static getInstance(bufferSize:number = 1024): ThreadUtils {if (!ThreadUtils.instance) {ThreadUtils.instance = new ThreadUtils(bufferSize);}return ThreadUtils.instance;}async writeToFile(content: string): Promise<boolean> {return new Promise((resolve, reject) => {setTimeout(() => {console.log("日志写入完成=" + content)console.log('pop element=' + content)resolve(true)}, 4000)})}lastTask:taskpool.Task | undefinedflag = falseasync product(log: string):Promise<boolean> {return new Promise<boolean>((resolve,reject)=>{let newLog = loglet task = new taskpool.Task(producer, this.i32a, this.ui8, newLog)if (this.lastTask) {task.addDependency(this.lastTask)}this.lastTask = tasktask.onReceiveData((success: boolean) => {if (!success) {this.flag = truethis.tempLogList.unshift(log)resolve(false)}})taskpool.execute(task).then(()=>{console.log('------taskpool.execute.then-----')resolve(true)});})}isWhile = falseasync startConsumer() {let task = new taskpool.Task(consumerTask, this.i32a, this.ui8)task.onReceiveData(async (hasSpace: boolean) => {if (hasSpace) {this.flag = falseif (this.tempLogList.length > 0 && this.isWhile == false){let item = this.tempLogList.shift()console.log('---item---'+ item)this.isWhile = truelet com = truewhile (item && this.flag == false && com){com = await this.product(item)item = this.tempLogList.shift()}this.isWhile = false}}})taskpool.execute(task)}}
5.页面UI应用
import { buffer, taskpool } from '@kit.ArkTS';
import { consumerTask } from '../consumer';
import { producer } from '../product';
import { router } from '@kit.ArkUI';
import { ThreadUtils } from '../ThreadUtils';@Entry
@Component
struct Index {timer = -1count = 0logTool = ThreadUtils.getInstance(32)aboutToAppear(): void {}@State inputText:string =''build() {Column({space: 20}) {TextInput({text: $$this.inputText}).width('80%')Button() {Text("生产日志").padding(10)}.backgroundColor(Color.Gray).onClick(async () => {this.timer = setInterval(()=>{this.logTool.writeLog ('item' + this.count)this.count += 1},1000)})Button() {Text("停止生产").padding(10)}.backgroundColor(Color.Gray).onClick(async () => {clearInterval(this.timer)// router.pushUrl({// url: 'pages/TaskPoolPage'// })})}.alignItems(HorizontalAlign.Center).justifyContent(FlexAlign.Center).height('100%').width('100%')}
}
相关文章:
鸿蒙多线程应用-taskPool
并发模型 并发模型是用来实现不同应用场景中并发任务的编程模型,常见的并发模型分为基于内存共享的并发模型和基于消息通信的并发模型。 Actor并发模型作为基于消息通信并发模型的典型代表,不需要开发者去面对锁带来的一系列复杂偶发的问题,同…...
【失败经验】将算法模型封装为安卓应用
背景:不懂安卓开发,希望能使用大模型编码完成安卓应用生成,调用算法模型进行预测。 模型准备: pip方案安装pcnn; 然后需要将pytorch训练完成的算法模型保存为torchscript模型,然后使用pcnn转换为ncnn的模…...

ABAP OOALV模板
自用模板,可能存在问题 一、主程序 *&---------------------------------------------------------------------* *& Report ZVIA_OO_ALV *&---------------------------------------------------------------------* REPORT ZVIA_OO_ALV.INCLUDE ZVI…...
YOLOv8-ultralytics-8.2.103部分代码阅读笔记-autobatch.py
autobatch.py ultralytics\utils\autobatch.py 目录 autobatch.py 1.所需的库和模块 2.def check_train_batch_size(model, imgsz640, ampTrue, batch-1): 3.def autobatch(model, imgsz640, fraction0.60, batch_sizeDEFAULT_CFG.batch): 1.所需的库和模块 # Ultraly…...

SycoTec 4060 ER-S德国高精密主轴电机如何支持模具的自动化加工?
SycoTec 4060 ER-S高速电主轴在模具自动化加工中的支持体现在以下几个关键方面: 1.高精度与稳定性:SycoTec 4060 ER-S锥面跳动小于1微米,确保了加工过程中的极高精度,这对于模具的复杂几何形状和严格公差要求至关重要。高精度加工…...
部署 DeepSpeed以推理 defog/sqlcoder-70b-alpha 模型
部署 DeepSpeed 以推理 defog/sqlcoder-70b-alpha 这样的 70B 模型是一个复杂的过程,涉及多个关键步骤。下面是详细的步骤,涵盖了从模型加载、内存优化到加速推理的全过程。 1. 准备环境 确保你的环境配置正确,以便能够顺利部署 defog/sqlc…...
Python网络爬虫基础
Python网络爬虫是一种自动化工具,用于从互联网上抓取信息。它通过模拟人类浏览网页的行为,自动地访问网站并提取所需的数据。网络爬虫在数据挖掘、搜索引擎优化、市场研究等多个领域都有广泛的应用。以下是Python网络爬虫的一些基本概念: 1.…...

每天五分钟机器学习:支持向量机数学基础之超平面分离定理
本文重点 超平面分离定理(Separating Hyperplane Theorem)是数学和机器学习领域中的一个重要概念,特别是在凸集理论和最优化理论中有着广泛的应用。该定理表明,在特定的条件下,两个不相交的凸集总可以用一个超平面进行分离。 定义与表述 超平面分离定理(Separating Hy…...
TCP/IP网络协议栈
TCP/IP网络协议栈是一个分层的网络模型,用于在互联网和其他网络中传输数据。它由几个关键的协议层组成,每一层负责特定的功能。以下是对TCP/IP协议栈的简要介绍: TCP/IP协议模型的分层 1. 应用层(Application Layer)…...
利用编程思维做题之最小堆选出最大的前10个整数
1. 理解问题 我们需要设计一个程序,读取 80,000 个无序的整数,并将它们存储在顺序表(数组)中。然后从这些整数中选出最大的前 10 个整数,并打印它们。要求我们使用时间复杂度最低的算法。 由于数据量很大,直…...

详解MVC架构与三层架构以及DO、VO、DTO、BO、PO | SpringBoot基础概念
🙋大家好!我是毛毛张! 🌈个人首页: 神马都会亿点点的毛毛张 今天毛毛张分享的是SpeingBoot框架学习中的一些基础概念性的东西:MVC结构、三层架构、POJO、Entity、PO、VO、DO、BO、DTO、DAO 文章目录 1.架构1.1 基本…...
Unity C# 影响性能的坑点
c用的时间长了怕unity的坑忘了,记录一下。 GetComponent最好使用GetComponent<T>()的形式, 继承自Monobehaviour的函数要避免空的Awake()、Start()、Update()、FixedUpdate().这些空回调会造成性能浪费 GetComponent方法最好避免在Update当中使用…...

工作学习:切换git账号
概括 最近工作用的git账号下发下来了,需要切换一下使用的账号。因为是第一次弄,不熟悉,现在记录一下。 打开设置 路径–git—git remotes,我这里选择项是Manage Remotes,点进去就可以了。 之后会出现一个输入框&am…...
量化交易系统开发-实时行情自动化交易-8.量化交易服务平台(一)
19年创业做过一年的量化交易但没有成功,作为交易系统的开发人员积累了一些经验,最近想重新研究交易系统,一边整理一边写出来一些思考供大家参考,也希望跟做量化的朋友有更多的交流和合作。 接下来会对于收集整理的33个量化交易服…...

Scala习题
姓名,语文,数学,英语 张伟,87,92,88 李娜,90,85,95 王强,78,90,82 赵敏,92,88,91 孙涛,…...

结构方程模型(SEM)入门到精通:lavaan VS piecewiseSEM、全局估计/局域估计;潜变量分析、复合变量分析、贝叶斯SEM在生态学领域应用
目录 第一章 夯实基础 R/Rstudio简介及入门 第二章 结构方程模型(SEM)介绍 第三章 R语言SEM分析入门:lavaan VS piecewiseSEM 第四章 SEM全局估计(lavaan)在生态学领域高阶应用 第五章 SEM潜变量分析在生态学领域…...

OpenCV图像基础处理:通道分离与灰度转换
在计算机视觉处理中,理解图像的颜色通道和灰度表示是非常重要的基础知识。今天我们通过Python和OpenCV来探索图像的基本组成。 ## 1. 图像的基本组成 在数字图像处理中,彩色图像通常由三个基本颜色通道组成: - 蓝色(Blue&#x…...

C++ 类和对象(类型转换、static成员)
目录 一、前言 二、正文 1.隐式类型转换 1.1隐式类型转换的使用 2.static成员 2.1 static 成员的使用 2.1.1static修辞成员变量 2.1.2 static修辞成员函数 三、结语 一、前言 大家好,我们又见面了。昨天我们已经分享了初始化列表:https://blog.c…...

【网络安全设备系列】12、态势感知
0x00 定义: 态势感知(Situation Awareness,SA)能够检测出超过20大类的云上安全风险,包括DDoS攻击、暴力破解、Web攻击、后门木马、僵尸主机、异常行为、漏洞攻击、命令与控制等。利用大数据分析技术,态势感…...

Linux介绍与安装指南:从入门到精通
1. Linux简介 1.1 什么是Linux? Linux是一种基于Unix的操作系统,由Linus Torvalds于1991年首次发布。Linux的核心(Kernel)是开源的,允许任何人自由使用、修改和分发。Linux操作系统通常包括Linux内核、GNU工具集、图…...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...

【Post-process】【VBA】ETABS VBA FrameObj.GetNameList and write to EXCEL
ETABS API实战:导出框架元素数据到Excel 在结构工程师的日常工作中,经常需要从ETABS模型中提取框架元素信息进行后续分析。手动复制粘贴不仅耗时,还容易出错。今天我们来用简单的VBA代码实现自动化导出。 🎯 我们要实现什么? 一键点击,就能将ETABS中所有框架元素的基…...

【若依】框架项目部署笔记
参考【SpringBoot】【Vue】项目部署_no main manifest attribute, in springboot-0.0.1-sn-CSDN博客 多一个redis安装 准备工作: 压缩包下载:http://download.redis.io/releases 1. 上传压缩包,并进入压缩包所在目录,解压到目标…...
Python 高级应用10:在python 大型项目中 FastAPI 和 Django 的相互配合
无论是python,或者java 的大型项目中,都会涉及到 自身平台微服务之间的相互调用,以及和第三发平台的 接口对接,那在python 中是怎么实现的呢? 在 Python Web 开发中,FastAPI 和 Django 是两个重要但定位不…...

归并排序:分治思想的高效排序
目录 基本原理 流程图解 实现方法 递归实现 非递归实现 演示过程 时间复杂度 基本原理 归并排序(Merge Sort)是一种基于分治思想的排序算法,由约翰冯诺伊曼在1945年提出。其核心思想包括: 分割(Divide):将待排序数组递归地分成两个子…...
拟合问题处理
在机器学习中,核心任务通常围绕模型训练和性能提升展开,但你提到的 “优化训练数据解决过拟合” 和 “提升泛化性能解决欠拟合” 需要结合更准确的概念进行梳理。以下是对机器学习核心任务的系统复习和修正: 一、机器学习的核心任务框架 机…...

网页端 js 读取发票里的二维码信息(图片和PDF格式)
起因 为了实现在报销流程中,发票不能重用的限制,发票上传后,希望能读出发票号,并记录发票号已用,下次不再可用于报销。 基于上面的需求,研究了OCR 的方式和读PDF的方式,实际是可行的ÿ…...