鸿蒙多线程开发——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.mzph.cn/pingmian/62027.shtml

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

相关文章

Android BottomNavigationView 底部导航栏使用详解

一、BottomNavigationView简介 BottomNavigationView是官方提供可以实现底部导航的组件&#xff0c;最多支持5个item&#xff0c;主要用于功能模块间的切换&#xff0c;默认会包含动画效果。 官方介绍地址&#xff1a;BottomNavigationView 二、使用BottomNavigationView a…

【大数据学习 | Spark-Core】Spark提交及运行流程

spark的集群运行结构 我们要选择第一种使用方式 命令组成结构 spark-submit [选项] jar包 参数 standalone集群能够使用的选项。 --master MASTER_URL #集群地址 --class class_name #jar包中的类 --executor-memory MEM #executor的内存 --executor-cores NUM # executor的…

React中事件处理和合成事件:理解与使用

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

[241125] X-CMD 发布 v0.4.14:webtop-Linux 容器桌面;支持 PowerShell 环境;轻松搭建并测试蜜罐环境等

目录 X-CMD 发布 v0.4.14&#x1f4c3;Changelog&#x1f427; webtop -- Linux 桌面容器&#x1f5a5;️ pwsh&#x1f4bb; elv|fish|nu|onsh|tcsh&#x1f40b; endlessh&#x1f40b; cowrie&#x1f4f2; mosh&#x1f4bb; mac -- Mac 实用功能&#x1f386; ascii&#…

Jmeter中的测试片段和非测试原件

1&#xff09;测试片段 1--测试片段 功能特点 重用性&#xff1a;将常用的测试元素组合成一个测试片段&#xff0c;便于在多个线程组中重用。模块化&#xff1a;提高测试计划的模块化程度&#xff0c;使测试计划更易于管理和维护。灵活性&#xff1a;可以通过模块控制器灵活地…

linux实时操作系统xenomai看门狗(watchdog)机制及作用介绍

版权声明&#xff1a;本文为本文为博主原创文章&#xff0c;转载请注明出处 https://www.cnblogs.com/wsg1100。如有错误&#xff0c;欢迎指正。 文章目录 一、前言PREEMPT-RT&#xff08;RT Throttling&#xff09; 一、xenomai watchdog介绍二、xenomai watchdog工作原理三、…

【C语言】字符串左旋的三种解题方法详细分析

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C语言 文章目录 &#x1f4af;前言&#x1f4af;题目描述&#x1f4af;方法一&#xff1a;逐字符移动法&#x1f4af;方法二&#xff1a;使用辅助空间法&#x1f4af;方法三&#xff1a;三次反转法&#x1f4af;方法对…

【大模型】LLaMA-Factory的环境配置、微调模型与测试

前言 【一些闲扯】 时常和朋友闲聊&#xff0c;时代发展这么快&#xff0c;在时代的洪流下&#xff0c;我们个人能抓住些什么呢。我问了大模型&#xff0c;文心一言是这样回答的&#xff1a; 在快速发展的时代背景下&#xff0c;个人确实面临着诸多挑战&#xff0c;但同时也充满…

Web 表单开发全解析:从基础到高级掌握 HTML 表单设计

文章目录 前言一、什么是 Web 表单?二、表单元素详解总结前言 在现代 Web 开发中,表单 是用户与后端服务交互的重要桥梁。无论是用户登录、注册、搜索,还是提交反馈,表单都无处不在。在本文中,我们将从基础入手,全面解析表单的核心知识点,并通过示例带你轻松掌握表单开…

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

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

打造优秀技术文档的三大方向

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

Xcode15(iOS17.4)打包的项目在 iOS12 系统上启动崩溃

0x00 启动崩溃 崩溃日志&#xff0c;只有 2 行&#xff0c;看不出啥来。 0x01 默认配置 由于我开发时&#xff0c;使用的 Xcode 14.1&#xff0c;打包在另外一台电脑 Xcode 15.3 Xcode 14.1 Build Settings -> Asset Catalog Compliter - Options Xcode 15.3 Build S…

如何使用GCC手动编译stm32程序

如何不使用任何IDE&#xff08;集成开发环境&#xff09;编译stm32程序? 集成开发环境将编辑器、编译器、链接器、调试器等开发工具集成在一个统一的软件中&#xff0c;使得开发人员可以更加简单、高效地完成软件开发过程。如果我们不使用KEIL,IAR等集成开发环境&#xff0c;…

QUICK 调试camera-xml解析

本文主要介绍如何在QUICK QCS6490使能相机模组。QCS6490的相机基于CameraX的框架&#xff0c;只需通过配置XML文件&#xff0c;设置相机模组的相关参数&#xff0c;就可以点亮相机。本文主要介绍Camera Sensor Module XML和Camera Sensor XML配置的解析&#xff0c;这中间需要c…

数据结构 (11)串的基本概念

一、串的定义 1.串是由一个或者多个字符组成的有限序列&#xff0c;一般记为&#xff1a;sa1a2…an&#xff08;n≥0&#xff09;。其中&#xff0c;s是串的名称&#xff0c;用单括号括起来的字符序列是串的值&#xff1b;ai&#xff08;1≤i≤n&#xff09;可以是字母、数字或…

汽车渲染领域:Blender 和 UE5 哪款更适用?两者区别?

在汽车渲染领域&#xff0c;选择合适的工具对于实现高质量的视觉效果至关重要。Blender和UE5&#xff08;Unreal Engine 5&#xff09;作为两大主流3D软件&#xff0c;各自在渲染动画方面有着显著的差异。本文将从核心定位与用途、工作流程、渲染技术和灵活性、后期处理与合成四…

开源加密库mbedtls及其Windows编译库

目录 1 项目简介 2 功能特性 3 性能优势 4 平台兼容性 5 应用场景 6 特点 7 Windows编译 8 编译静态库及其测试示例下载 1 项目简介 Mbed TLS是一个由ARM Maintained的开源项目&#xff0c;它提供了一个轻量级的加密库&#xff0c;适用于嵌入式系统和物联网设备。这个项…

C语言数据结构——详细讲解 双链表

从单链表到双链表&#xff1a;数据结构的演进与优化 前言一、单链表回顾二、单链表的局限性三、什么是双链表四、双链表的优势1.双向遍历2.不带头双链表的用途3.带头双链表的用途 五、双链表的操作双链表的插入操作&#xff08;一&#xff09;双链表的尾插操作&#xff08;二&a…

MYSQL 表的增删改查(上)

目录 1.新增数据 2.查询数据 一般查询 去重查询 排序查询 关于NULL 条件查询 分页查询 1.新增数据 语法&#xff1a;insert into 表名[(字段1&#xff0c;字段2...)] values (值&#xff0c;值....); 插入一条新数据行&#xff0c;前面指定的列&#xff0c;要与后面v…

Docker pull镜像拉取失败

因为一些原因&#xff0c;很多镜像仓库拉取镜像失败&#xff0c;所以需要更换不同的镜像&#xff0c;这是2024/11/25测试可用的仓库。 标题1、 更换镜像仓库的地址&#xff0c;编辑daemon.json文件 vi /etc/docker/daemon.json标题2、然后将下面的镜像源放进去或替换掉都可以…