鸿蒙多线程开发——sendable共享容器

1、异步锁机制

在介绍共享容器之前,先介绍异步锁机制。

为了解决多线程并发任务间的数据竞争问题,ArkTS引入了异步锁能力。异步锁可能会被类对象持有,因此为了更方便地在并发实例间获取同一个异步锁对象,AsyncLock对象支持跨线程引用传递。

由于ArkTS语言支持异步操作,阻塞锁容易产生死锁问题,因此在ArkTS中仅支持异步锁(非阻塞式锁)。同时,异步锁还可以用于保证单线程内的异步任务时序一致性,防止异步任务时序不确定导致的同步问题。

使用异步锁的方法需要标记为async,调用方需要使用await修饰,才能保证时序正确。

为了解决@Sendable共享对象在不同线程修改共享变量导致的竞争问题,可以采用异步锁进行数据保护。Sendable共享对象在之前文章中有介绍👉🏻鸿蒙多线程开发——线程间数据通信对象03(sendable)

异步锁使用示例如下(关注9~11行,15~17行):

import { ArkTSUtils, taskpool } from '@kit.ArkTS';@Sendableexport class A {  private count_: number = 0;  lock_: ArkTSUtils.locks.AsyncLock = new ArkTSUtils.locks.AsyncLock();  public async getCount(): Promise<number> {    return this.lock_.lockAsync(() => {      return this.count_;    })  }  public async increaseCount() {    await this.lock_.lockAsync(() => {      this.count_++;    })  }}@Concurrentasync function printCount(a: A) {  console.info("InputModule: count is:" + await a.getCount());}@Entry@Componentstruct Index {  @State message: string = 'Hello World';  build() {    RelativeContainer() {      Text(this.message)        .id('HelloWorld')        .fontSize(50)        .fontWeight(FontWeight.Bold)        .alignRules({          center: { anchor: '__container__', align: VerticalAlign.Center },          middle: { anchor: '__container__', align: HorizontalAlign.Center }        })        .onClick(async () => {          let a: A = new A();          await taskpool.execute(printCount, a);        })    }    .height('100%')    .width('100%')  }}

2、共享容器

ArkTS共享容器(@arkts.collections (ArkTS容器集))是一种在并发任务间共享传输的容器类,可以用于并发场景下的高性能数据传递。

ArkTS共享容器在多个并发任务间传递时,其默认行为是引用传递,支持多个并发任务可以操作同一个容器实例。另外,也支持拷贝传递,即每个并发任务持有一个ArkTS容器实例。

ArkTS共享容器并不是线程安全的,内部使用了fail-fast(快速失败)机制,即当检测多个并发实例同时对容器进行结构性改变时,会触发异常。因此,在容器内修改属性的场景下,我们需要使用ArkTS提供的异步锁机制保证ArkTS容器的安全访问。

ArkTS共享容器包含如下几种:Array、Map、Set、TypedArray(Int8Array、Uint8Array、Int16Array、Uint16Array、Int32Array、Uint32Array、Uint8ClampedArray、Float32Array)、ArrayBuffer等。

📢 注意,这里说的容器是@arkts.collections中创建的ArkTs容器(多线程共享容器),并非平时普通使用的容器。

一个Array容器的使用案例如下:​​​​​​​

import { ArkTSUtils, collections, taskpool } from '@kit.ArkTS';@Concurrentasync function add(arr: collections.Array<number>, lock: ArkTSUtils.locks.AsyncLock) { await lock.lockAsync(() => {  // 如果不添加异步锁,任务会因为数据竞争冲突,导致抛异常失败   arr[0]++; })}@Entry@Componentstruct Index {  @State message: string = 'Hello World';  build() {    RelativeContainer() {      Text(this.message)        .id('HelloWorld')        .fontSize(50)        .fontWeight(FontWeight.Bold)        .alignRules({          center: { anchor: '__container__', align: VerticalAlign.Center },          middle: { anchor: '__container__', align: HorizontalAlign.Center }        })        .onClick(() => {          let taskGroup = new taskpool.TaskGroup();          let lock = new ArkTSUtils.locks.AsyncLock();          let arr = collections.Array.create<number>(1, 0);          let count = 1000;          while (count--) {            taskGroup.addTask(add, arr, lock);          }          taskpool.execute(taskGroup).then(() => {            console.info(`Return success: ${arr[0]} === ${count}`);          }).catch((e: Error) => {            console.error("Return error.");          })        })    }    .height('100%')    .width('100%')  }}

3、共享容器注意事项

在@arkts.collections (ArkTS容器集)中提供的容器与前端开发中JS所使用的容器大体上保持一致。但有一部分存在差异。下面对这些差异做一些归类。

📢📢 注意,这里说的容器是@arkts.collections中创建的ArkTs容器(多线程共享容器),并非平时普通使用的容器。

有差异的有:Array、Map、Set、TypedArray。(ArrayBuffer没有差异)

其中TypedArray是以下几种类型的统称:

    • Int8Array、Uint8Array、Uint8ClampedArray

    • Int16Array、Uint16Array

    • Int32Array、Uint32Array、Float32Array

3.1、Array与JS原生API的差异

支持原生容器Array通过collections.Array.from方法转换为ArkTS Array容器;支持通过原生容器Array的from方法将ArkTS Array容器转换为原生容器Array。

有差异的部分罗列如下:

原生API方法ArkTS容器集方法在ArkTS容器中的差异表现
length: numberreadonly length: number为了防止undefined扩散,不允许设置length。
new(arrayLength ?: number): any[]static create(arrayLength: number, initialValue: T): Array为了防止undefined扩散,构造函数中必须提供一个初始值的构造函数。
new <T>(...items: T[]): T[]constructor(first: T, ...left: T[])为了防止undefined扩散,构造函数中必须提供一个初始值的构造函数,继承场景下,无法调用该函数进行对象构造。
pop(): T | undefinedpop(): T | undefined不允许在遍历、访问过程中进行元素的增、删、改操作,否则会抛出异常。
push(...items: T[]): numberpush(...items: T[]): number不允许在遍历、访问过程中进行元素的增、删、改操作,否则会抛出异常。
concat(...items: ConcatArray<T>[]): T[]concat(...items: ConcatArray<T>[]): Array<T>不允许在遍历、访问过程中进行元素的增、删、改操作,否则会抛出异常。
concat(...items: (T | ConcatArray<T>)[]): T[]concat(...items: ConcatArray<T>[]): Array<T>不允许在遍历、访问过程中进行元素的增、删、改操作,否则会抛出异常。
shift(): T | undefinedshift(): T | undefined不允许在遍历、访问过程中进行元素的增、删、改操作,否则会抛出异常。
sort(compareFn?: (a: T, b: T) => number): thissort(compareFn?: (a: T, b: T) => number): Array<T>1. 不允许在遍历、访问过程中进行元素的增、删、改操作,否则会抛出异常。2. 继承场景下,无法获得实际类型的返回值。
unshift(...items: T[]): numberunshift(...items: T[]): number不允许在遍历、访问过程中进行元素的增、删、改操作,否则会抛出异常。
forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): voidforEach(callbackFn: (value: T, index: number, array: Array<T>) => void): voidArkTS不支持this,因此不支持thisArg参数。
map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]map<U>(callbackFn: (value: T, index: number, array: Array<T>) => U): Array<U>ArkTS不支持this,因此不支持thisArg参数。
filter(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): T[]filter(predicate: (value: T, index: number, array: Array<T>) => boolean): Array<T>ArkTS不支持this,因此不支持thisArg参数。
[n: number]: T[index: number]: T不允许在遍历、访问过程中进行元素的增、删、改操作,否则会抛出异常。
findIndex(predicate: (value: T, index: number, obj: T[]) => unknown, thisArg?: any): numberfindIndex(predicate: (value: T, index: number, obj: Array<T>) => boolean): numberArkTS不支持this,因此不支持thisArg参数。
fill(value: T, start?: number, end?: number): thisfill(value: T, start?: number, end?: number): Array<T>1. 不允许在遍历、访问过程中进行元素的增、删、改操作,否则会抛出异常。2. 继承场景下,无法获得实际类型的返回值。

3.2、TypedArray与JS原生API的差异

支持原生容器TypedArray通过collections.TypedArray.from方法转换为ArkTS TypedArray容器;

支持通过原生容器TypedArray的from方法将ArkTS TypedArray容器转换为原生容器TypedArray。

以Int8Array为例,有差异部分罗列如下:

原生API方法ArkTS容器集方法在ArkTS容器中的差异表现
copyWithin(target: number, start: number, end?: number): thiscopyWithin(target: number, start: number, end?: number): Int8Array不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。
every(predicate: (value: number, index: number, array: Int8Array) => unknown, thisArg?: any): booleanevery(predicate: TypedArrayPredicateFn<number, Int8Array>): boolean1. 不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。2. ArkTS不支持this,因此不支持thisArg参数。
fill(value: number, start?: number, end?: number): thisfill(value: number, start?: number, end?: number): Int8Array不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。
filter(predicate: (value: number, index: number, array: Int8Array) => any, thisArg?: any): Int8Arrayfilter(predicate: TypedArrayPredicateFn<number, Int8Array>): Int8Array1. 不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。2. ArkTS不支持this,因此不支持thisArg参数。
find(predicate: (value: number, index: number, obj: Int8Array) => boolean, thisArg?: any): number | undefinedfind(predicate: TypedArrayPredicateFn<number, Int8Array>): number | undefined1. 不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。2. ArkTS不支持this,因此不支持thisArg参数。
findIndex(predicate: (value: number, index: number, obj: Int8Array) => boolean, thisArg?: any): numberfindIndex(predicate: TypedArrayPredicateFn<number, Int8Array>): numberArkTS不支持this,因此不支持thisArg参数。
forEach(callbackfn: (value: number, index: number, array: Int8Array) => void, thisArg?: any): voidforEach(callbackFn: (value: number, index: number, array: Int8Array) => void): void1. 不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。2. ArkTS不支持this,因此不支持thisArg参数。
map(callbackfn: (value: number, index: number, array: Int8Array) => number, thisArg?: any): Int8Arraymap(callbackFn: TypedArrayForEachCallback<number, Int8Array>): Int8Array1. 不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。2. ArkTS不支持this,因此不支持thisArg参数。
set(array: ArrayLike<number>, offset?: number): voidset(array: ArrayLike<number>, offset?: number): void不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。
some(predicate: (value: number, index: number, array: Int8Array) => unknown, thisArg?: any): booleansome(predicate: TypedArrayPredicateFn<number, Int8Array>): booleanArkTS不支持this,因此不支持thisArg参数。
sort(compareFn?: (a: number, b: number) => number): thissort(compareFn?: TypedArrayCompareFn<number>): Int8Array1. 不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。2. 继承场景下,无法获得实际类型的返回值。
subarray(begin?: number, end?: number): Int8Arraysubarray(begin?: number, end?: number): Int8Array不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。
[index: number]: number[index: number]: number不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。
from<T>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => number, thisArg?: any): Int8Arraystatic from<T>(arrayLike: ArrayLike<T>, mapFn: TypedArrayFromMapFn<T, number>): Int8ArrayArkTS不支持this,因此不支持thisArg参数。
from(arrayLike: Iterable<number>, mapfn?: (v: number, k: number) => number, thisArg?: any): Int8Arraystatic from(arrayLike: Iterable<number>, mapFn?: TypedArrayFromMapFn<number, number>): Int8ArrayArkTS不支持this,因此不支持thisArg参数。

3.3、Map与JS原生API的差异

差异部分罗列如下:

原生API方法ArkTS容器集方法在ArkTS容器中的差异表现
readonly size: numberreadonly size: number不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。
clear(): voidclear(): void不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。
delete(key: K): booleandelete(key: K): boolean不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。
forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): voidforEach(callbackFn: (value: V, key: K, map: Map<K, V>) => void): void1. 不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。2. ArkTS不支持this,因此不支持thisArg参数。
get(key: K): V | undefinedget(key: K): V | undefined不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。
has(key: K): booleanhas(key: K): boolean不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。
set(key: K, value: V): thisset(key: K, value: V): Map<K, V>不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。
new <K, V>(entries?: readonly (readonly [K, V])[] | null): Map<K, V>constructor(entries?: readonly (readonly [K, V])[] | null)构造时传入的k,v键值不能是非Sendable数据,否则编译会报错。

3.4、Set与JS原生API的差异

差异部分罗列如下:

原生API方法ArkTS容器集方法在ArkTS容器中的差异表现
readonly size: numberreadonly size: numberSendable类和接口中不允许使用计算属性名称(arkts-sendable-compated-prop-name)。
add(value: T): thisadd(value: T): Set<T>不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。
clear(): voidclear(): void不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。
delete(value: T): booleandelete(value: T): boolean不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。
forEach(callbackfn: (value: T, value2: T, set: Set<T>) => void, thisArg?: any): voidforEach(callbackFn: (value: T, value2: T, set: Set<T>) => void): void1. 不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。2. ArkTS不支持this,因此不支持thisArg参数。
has(value: T): booleanhas(value: T): boolean不允许在遍历、访问过程中进行元素的增、删、改操作否则会抛出异常。
values(): IterableIterator<T>values(): IterableIterator<T>Sendable类和接口中不允许使用计算属性名称(arkts-sendable-compated-prop-name)。
new <T = any>(values?: readonly T[] | null): Set<T>constructor(values?: readonly T[] | null)构造时传入数据不能是非Sendable数据,否则编译会报错。

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

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

相关文章

jvm核心组件介绍

1. 类加载器&#xff08;ClassLoader&#xff09;&#xff1a; • 想象它是一个快递员&#xff0c;负责把Java类&#xff08;.class文件&#xff09;这个“包裹”从磁盘这个“发货地”送到JVM内部这个“目的地”。类加载器确保每个类只被加载一次&#xff0c;并维护一个类的层级…

目标检测,图像分割,超分辨率重建

目标检测和图像分割 目标检测和图像分割是计算机视觉中的两个不同任务&#xff0c;它们的输出形式也有所不同。下面我将分别介绍这两个任务的输出。图像分割又可以分为&#xff1a;语义分割、实例分割、全景分割。 语义分割&#xff08;Semantic Segmentation&#xff09;&…

Python编程技巧:多变量赋值的优雅艺术

在Python编程的世界里&#xff0c;有许多令人惊叹的语法特性&#xff0c;而多变量赋值就像是一颗闪耀的明珠&#xff0c;它不仅让代码更优雅&#xff0c;还能提升程序的执行效率。今天我们就深入探讨这个看似简单却蕴含深意的编程技巧。 基础认识 传统的变量赋值方式&#xff…

CentOS 7 安装部署 KVM

1.关闭虚拟机 打开相关选项 打开虚拟机centos7 连接xshell 测试网络&#xff0c;现在就是没问题的&#xff0c;因为我们要使用网络源 安装 GNOME 桌面环境 安装KVM 模块 安装KVM 调试工具 构建虚拟机的命令行工具 qemu 组件,创建磁盘、启动虚拟机等 输入这条命令&#xff0c;…

微信小程序学习指南从入门到精通

&#x1f5fd;微信小程序学习指南从入门到精通&#x1f5fd; &#x1f51d;微信小程序学习指南从入门到精通&#x1f51d;✍前言✍&#x1f4bb;微信小程序学习指南前言&#x1f4bb;一、&#x1f680;文章列表&#x1f680;二、&#x1f52f;教程文章的好处&#x1f52f;1. ✅…

【C++】读取数量不定的输入数据

读取数量不定的输入数据 似乎是一个很实用的东西&#xff1f; 问题&#xff1a; 我们如何对用户输入的一组数&#xff08;事先不知道具体有多少个数&#xff09;求和&#xff1f; 这需要不断读取数据直至没有新的输入为止。&#xff08;所以我们的代码就是这样设计的&#x…

基于vite创建的react18项目的单元测试

题外话 最近一个小伙伴进了字节外包&#xff0c;第一个活就是让他写一个单元测试。 嗯&#xff0c;说实话&#xff0c;在今天之前我只知道一些理论&#xff0c;但是并没有实操过&#xff0c;于是我就试验了一下。 通过查询资料&#xff0c;大拿们基本都说基于vite的项目&…

如何用通义灵码助力项目开发 | OceanBase obdiag 项目共建实践

本文来自 obdiag 项目共建的用户分享 一、背景 我的数据库探索之旅始于OceanBase。作为一位满怀好奇心的DBA&#xff0c;我内心始终怀揣着对数据库内部运作机制的无尽向往。开源如同一把钥匙&#xff0c;为我们这些求知欲旺盛的“好奇猫”解锁了通往新知的神秘大门。在众多分布…

idea_卸载与安装

卸载与安装 卸载1、设置 -> 应用2、查找到应用&#xff0c;点击卸载3、把删除记录和设置都勾选上4、删除其它几个位置的残留 安装1、下载安装包2、欢迎安装 -> Next3、选择安装目录 -> Next4、创建快捷图标和添加到环境变量5、确认文件夹的名称 -> Install6、完成安…

day01

Hm-Footer.vue <template><div class"hm-footer">我是hm-footer</div></template><script>export default {}</script><style>.hm-footer{height:100px;line-height:100px;text-align:center;font-size:30px;background-…

NLP 1、人工智能与NLP简介

人人都不看好你&#xff0c;可偏偏你最争气 —— 24.11.26 一、AI和NLP的基本介绍 1.人工智能发展流程 弱人工智能 ——> 强人工智能 ——> 超人工智能 ① 弱人工智能 人工智能算法只能在限定领域解决特定的问题 eg&#xff1a;特定场景下的文本分类、垂直领域下的对…

基于混合ABC和A*算法复现

基于混合ABC和A*算法复现 一、背景介绍二、算法原理&#xff08;一&#xff09;A*算法原理&#xff08;二&#xff09;人工蜂群算法原理&#xff08;三&#xff09;混合ABC和A*算法策略 三、代码实现&#xff08;一&#xff09;数据准备&#xff08;二&#xff09;关键函数实现…

解决SpringBoot连接Websocket报:请求路径 404 No static resource websocket.

问题发现 最近在工作中用到了WebSocket进行前后端的消息通信&#xff0c;后端代码编写完后&#xff0c;测试一下是否连接成功&#xff0c;发现报No static resource websocket.&#xff0c;看这个错貌似将接口变成了静态资源来访问了&#xff0c;第一时间觉得是端点没有注册成…

VITE+VUE3+TS环境搭建

前言&#xff08;与搭建项目无关&#xff09;&#xff1a; 可以安装一个node管理工具&#xff0c;比如nvm&#xff0c;这样可以顺畅的切换vue2和vue3项目&#xff0c;以免出现项目跑不起来的窘境。我使用的nvm&#xff0c;当前node 22.11.0 目录 搭建项目 添加状态管理库&…

红外小目标检测

目录 背景概述算法原理演示效果核心逻辑 使用方式基础镜像配置环境直接运行 参考文献 文章声明&#xff0c;非广告&#xff0c;仅个人体验。 背景 红外图像在许多领域中都有所应用。例如军事领域中&#xff0c;经常需要通过红外成像设备对远距离的目标进行侦察和监视&#xff…

【滑动窗口】找到字符串中所有字母异位词

文章目录 找到字符串中所有字母异位词 class Solution { public:vector<int> findAnagrams(string s, string p) {vector<int> ret;int sLen s.size(), pLen p.size(), validChar;// 母串长度比子串长度还小 直接返回空vectorif (sLen < pLen)return ret;// …

nodepad配置c/c++ cmd快速打开创建项目文件

前提:下载MinGw,并且配置环境变量 点击阅读次篇文章配置MinGw 无论是哪个编译器&#xff0c;执行c文件都是经历以下步骤: 编译文件生成exe文件执行该exe文件 我们先手动完成这两部 手动编译文件使用指令 gcc {你的c文件} -o {生成文件名}生成exe文件 第二步运行exe直接点击该文…

Opencv+ROS实现颜色识别应用

目录 一、工具 二、原理 概念 本质 三、实践 添加发布话题 主要代码 四、成果 五、总结 一、工具 opencvros ubuntu18.04 摄像头 二、原理 概念 彩色图像&#xff1a;RGB&#xff08;红&#xff0c;绿&#xff0c;蓝&#xff09; HSV图像&#xff1a;H&#xff0…

Vue.Draggable使用nested-with-vmodel进行拖拽

Vue.Draggable使用nested-with-vmodel进行拖拽 1. 介绍 ‌draggable‌是一个基于Sortable.js的Vue组件&#xff0c;用于实现拖拽功能。它支持触摸设备、拖拽和选择文本、智能滚动、不同列表之间的拖拽等功能&#xff0c;并且与Vue的视图模型同步刷新&#xff0c;兼容Vue2的过…

【湿度数据处理】中国地面气候资料日值数据集(V3.0)(MATLAB全代码)

【湿度数据处理】中国地面气候资料日值数据集 处理1:数据范围筛选处理2:缺测数据筛查处理3:缺测数据插补参考基于此博客完成各要素数据提取后-【数据集处理】中国地面气候资料日值数据集(V3.0)(含MATLAB全代码),进行后续数据筛选及缺测处理,此处以湿度数据为例。 提取到的…