鸿蒙多线程应用-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%')}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/62315.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaScript实用工具lodash库

Lodash中文文档: Lodash 简介 | Lodash中文文档 | Lodash中文网 Lodash是一个功能强大、易于使用的JavaScript实用工具库&#xff0c;它提供了丰富的函数和工具&#xff0c;能够方便地处理集合、字符串、数值、函数等多种数据类型。通过使用Lodash&#xff0c;开发者可以大幅…

数据结构-最短路径问题

一.问题分类 二.无权图单源最短路算法 dist[]数组记录的是个个顶点到源点的距离这个数组的下标表示顶点 源点到自己的距离是0,dist[s]0 path[]数组记录的是这个顶点的前驱&#xff0c;可以同过这个数组找到源点到个个顶点的距离 代码如下 void Unweighted(MGraph Graph, Ver…

ulimit -n是1024无法启动redis

ulimit -n 命令显示的是当前 shell 会话中可以打开的最大文件描述符数。如果这个值设置得太低&#xff0c;可能会导致 Redis 无法启动&#xff0c;因为 Redis 需要大量的文件描述符来处理客户端连接、持久化文件等。 默认情况下&#xff0c;Redis 可能需要更多的文件描述符&am…

Vue.js 实现用户注册功能

在本篇博客中&#xff0c;我们将通过一个简单的例子来展示如何使用 Vue.js 来实现一个用户注册功能。我们将创建一个包含用户名、邮箱和密码输入的表单&#xff0c;并在用户点击“创建账号”按钮时进行简单的验证。 完整代码 <!DOCTYPE html> <html lang"en&q…

transformers训练(NLP)阅读理解(多项选择)

简介 在阅读理解任务中&#xff0c;有一种通过多项选择其中一个答案来训练机器的阅读理解。比如&#xff1a;给定一个或多个文档h,以及一个问题S和对应的多个答案候选&#xff0c;输出问题S的答案E&#xff0c;E是答案候选中的某一个选项。 这样的目的就是通过文档&#xff0c…

【Java 学习】面向程序的三大特性:封装、继承、多态

引言 1. 封装1.1 什么是封装呢&#xff1f;1.2 访问限定符1.3 使用封装 2. 继承2.1 为什么要有继承&#xff1f;2.2 继承的概念2.3 继承的语法2.4 访问父类成员2.4.1 子类中访问父类成员的变量2.4.2 访问父类的成员方法 2.5 super关键字2.6 子类的构造方法 3. 多态3.1 多态的概…

impala入门与实践

1.impala基本介绍 impala是cloudera提供的一款高效率的sql查询工具&#xff0c;提供实时的查询效果&#xff0c;官方测试性能比hive快10到100倍&#xff0c;其sql查询比sparkSQL还要更加快速&#xff0c;号称是当前大数据领域最快的查询sql工具。impala是参照谷歌的新三篇论文…

shell查看服务器的内存和CPU,实时使用情况

要查看服务器的内存和 CPU 实时使用情况&#xff0c;可以使用以下方法和命令&#xff1a; 1. 使用 top 运行 top 命令以显示实时的系统性能信息&#xff0c;包括 CPU 和内存使用情况。 top按 q 退出。输出内容包括&#xff1a; CPU 使用率&#xff1a;位于顶部&#xff0c;标…

java中链表的数据结构的理解

在 Java 中&#xff0c;链表是一种常见的数据结构&#xff0c;可以通过类的方式实现自定义链表。以下是关于 Java 中链表的数据结构和实现方式的详细介绍。 1. 自定义链表结构 Java 中链表通常由一个节点类 (ListNode) 和可能的链表操作类构成。 节点类 (ListNode) 这是链表…

结构方程模型(SEM)入门到精通:lavaan VS piecewiseSEM、全局估计/局域估计;潜变量分析、复合变量分析、贝叶斯SEM在生态学领域应用

目录 第一章 夯实基础 R/Rstudio简介及入门 第二章 结构方程模型&#xff08;SEM&#xff09;介绍 第三章 R语言SEM分析入门&#xff1a;lavaan VS piecewiseSEM 第四章 SEM全局估计&#xff08;lavaan&#xff09;在生态学领域高阶应用 第五章 SEM潜变量分析在生态学领域…

2.mybatis整体配置

文章目录 mybatis-config.xml介绍SqlSessionFactoryBuilderXMLConfigBuilderpropertiessetting类型别名&#xff08;typeAliases&#xff09;扫描插件(plugins)解析objectFactory(对象工厂)解析objectWrapperFactory解析reflectorFactorysettingsElement()方法环境配置&#xf…

把本地新项目初始化传到github

在本地项目根目录下初始化Git仓库 git init将项目文件添加到Git仓库,接下来&#xff0c;你需要将项目中的文件添加到Git仓库中。可以使用git add命令来添加文件或目录。如果你想要添加所有文件&#xff0c;可以使用.来表示当前目录中的所有文件&#xff1a; git add .提交项目…

软件测试丨Pytest 第三方插件与 Hook 函数

Pytest不仅是一个用于编写简单和复杂测试的框架&#xff0c;还有大量的第三方插件以及灵活的Hook函数供我们使用&#xff0c;这些功能大大增强了其在软件测试中的应用。通过使用Pytest&#xff0c;测试开发变得简便、安全、高效&#xff0c;同时也能帮助我们更快地修复Bug&…

小米PC电脑手机互联互通,小米妙享,小米电脑管家,老款小米笔记本怎么使用,其他品牌笔记本怎么使用,一分钟教会你

说在前面 之前我们体验过妙享中心&#xff0c;里面就有互联互通的全部能力&#xff0c;现在有了小米电脑管家&#xff0c;老款的笔记本竟然用不了&#xff0c;也可以理解&#xff0c;毕竟老款笔记本做系统研发的时候没有预留适配的文件补丁&#xff0c;至于其他品牌的winPC小米…

python爬虫案例——猫眼电影数据抓取之字体解密,多套字体文件解密方法(20)

文章目录 1、任务目标2、网站分析3、代码编写1、任务目标 目标网站:猫眼电影(https://www.maoyan.com/films?showType=2) 要求:抓取该网站下,所有即将上映电影的预约人数,保证能够获取到实时更新的内容;如下: 2、网站分析 进入目标网站,打开开发者模式,经过分析,我…

一分钟食用前端测试框架Jest

安装 其实食用Jest是很简单的,我们只需要安装Jest即可 npm install --save-dev jestyarn add --dev jestpnpm add --save-dev jest ESmodule 本身来说,Jest是不支持Esmodule的,他支持CommonJS,我们需要Babel改一下 npm i --save-dev babel-jest babel/core babel/preset-env …

MySQL中的ROW_NUMBER窗口函数简单了解下

ROW_NUMBER() 是 MySQL8引入的窗口函数之一&#xff0c;它为查询结果集中的每一行分配一个唯一的顺序号&#xff08;行号&#xff09;。这个顺序号是基于窗口函数的 ORDER BY 子句进行排序的&#xff0c;可以根据指定的排序顺序生成连续的整数值。 ROW_NUMBER() 在分页、去重、…

从 App Search 到 Elasticsearch — 挖掘搜索的未来

作者&#xff1a;来自 Elastic Nick Chow App Search 将在 9.0 版本中停用&#xff0c;但 Elasticsearch 拥有你构建强大的 AI 搜索体验所需的一切。以下是你需要了解的内容。 生成式人工智能的最新进展正在改变用户行为&#xff0c;激励开发人员创造更具活力、更直观、更引人入…

CTF之密码学(费纳姆密码)

一、作为二进制替换密码的费纳姆密码 定义&#xff1a;费纳姆密码是一种由二进制产生的替换密码&#xff0c;也被称为弗纳姆密码&#xff08;Vernam cipher&#xff09;。它采用二进制表示法&#xff0c;将明文转化为二进制数字&#xff0c;并通过与密钥进行模2加法运算来产生密…

若依框架部署在网站一个子目录下(/admin)问题(

部署在子目录下首先修改vue.config.js文件&#xff1a; 问题一&#xff1a;登陆之后跳转到了404页面问题&#xff0c;解决办法如下&#xff1a; src/router/index.js 把404页面直接变成了首页&#xff08;大佬有啥优雅的解决办法求告知&#xff09; 问题二&#xff1a;退出登录…