当前位置: 首页 > news >正文

Sendable装饰器的使用

Sendable对象是符合ArkTS语言规范的可共享对象,需通过@Sendable装饰器标记,并且满足Sendable约束。

@Sendable装饰器

装饰class、function

Sendable使用规则与约束

  1. Sendable类必须继承自Sendable类

  2. 非Sendable类禁止实现Sendable接口

    import { lang } from '@kit.ArkTS';type ISendable = lang.ISendable;interface I extends ISendable {};class B implements I {};  // I是sendable interface,B不能实现,编译报错
    
  3. Sendable类/接口成员变量:不支持使用!断言、不支持使用计算属性名

计算属性名

  • 普通属性名(固定属性名)
const obj = {name: "张三",     // 固定属性名 "name"age: 25          // 固定属性名 "age"
};
  • 计算属性名(动态属性名)
const propName = "userName";
const dynamicKey = "Age";const obj = {[propName]: "李四",        // 计算属性名,值为 "userName"["user" + dynamicKey]: 30, // 计算属性名,值为 "userAge"["total" + "Score"]: 100   // 计算属性名,值为 "totalScore"
};
  1. 泛型类中的Sendable类、SendableLruCache、collections.Array、collections.Map和collections.Set的模板类型必须是Sendable类型

  2. Sendable类的内部不允许使用当前模块内上下文环境中定义的变量

    Sendable类内部只能访问:

    1. top level 的 Sendable class 对象(类本身,不是实例
    2. 静态成员(static 成员)
    3. 其他top level的Sendable类
  3. @Sendable装饰器仅支持修饰类和函数

  4. 禁止使用对象字面量 数组字面量初始化Sendable对象

    import { collections } from '@kit.ArkTS';let arr2: collections.Array<number> = [1, 2, 3]; // 不是Sendable类型,编译报错
    let arr3: number[] = [1, 2, 3]; // 不是Sendable类型,正例,不报错
    let arr4: number[] = new collections.Array<number>(1, 2, 3); // 编译报错
    
  5. 箭头函数不可标记为Sendable

    @Sendable
    type SendableFuncType = () => void;
    let func: SendableFuncType = () => {}; // 编译报错@Sendable
    class SendableClass {func: SendableFuncType = () => {}; // 编译报错
    }
    

异步锁

为了防止@Sendable共享对象在不同线程中修改共享变量导致的竞争问题,可以使用异步锁保护数据。

import { ArkTSUtils, taskpool } from '@kit.ArkTS';@Sendable
export class A {private count_: number = 0;lock_: ArkTSUtils.locks.AsyncLock = new ArkTSUtils.locks.AsyncLock();public getCount(): Promise<number> {// 对需要保护的数据加异步锁return this.lock_.lockAsync(() => {return this.count_;})}public async increaseCount() {// 对需要保护的数据加异步锁await this.lock_.lockAsync(() => {this.count_++;})}
}@Concurrent
async function printCount(a: A) {a.increaseCount();console.info("InputModule: count is:" + await a.getCount());
}@Entry
@Component
struct 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 () => {// 创建sendable对象alet a: A = new A();// 将实例a传递给子线程await taskpool.execute(printCount, a);})}.height('100%').width('100%')}
}

异步等待

ArkTS引入了异步任务的等待和被唤醒能力,以解决多线程任务时序控制问题

import { ArkTSUtils, taskpool } from '@kit.ArkTS';//通知所有等待线程
@Concurrent
function notifyAll(conditionVariable: ArkTSUtils.locks.ConditionVariable) {conditionVariable.notifyAll();
}//通知一个等待线程
@Concurrent
function notifyOne(conditionVariable: ArkTSUtils.locks.ConditionVariable) {conditionVariable.notifyOne();
}//无限等待
@Concurrent
async function wait(conditionVariable: ArkTSUtils.locks.ConditionVariable) {await conditionVariable.wait().then(() => {console.info(`TaskPool Thread Wait: success`);});
}//超时等待
@Concurrent
async function waitFor(conditionVariable: ArkTSUtils.locks.ConditionVariable) {await conditionVariable.waitFor(3000).then(() => {console.info(`TaskPool Thread WaitFor: success`);});
}@Entry
@Component
struct Index {@State message: string = 'Hello World';build() {Row() {Column() {Text(this.message).fontSize(50).fontWeight(FontWeight.Bold).onClick(() => {// 1. 方式1:匿名条件变量// 创建conditionVariable对象const conditionVariable: ArkTSUtils.locks.ConditionVariable = new ArkTSUtils.locks.ConditionVariable();// 将实例conditionVariable传递给wait线程taskpool.execute(wait, conditionVariable);// 将实例conditionVariable传递给notifyAll线程,唤醒wait线程,日志输出"TaskPool Thread Wait: success"taskpool.execute(notifyAll, conditionVariable);// 将实例conditionVariable传递给waitFor线程taskpool.execute(waitFor, conditionVariable);// 将实例conditionVariable传递给notifyOne线程,唤醒waitFor线程,日志输出"TaskPool Thread WaitFor: success"taskpool.execute(notifyOne, conditionVariable);// 2. 方式2:命名条件变量// 创建有name的conditionVariable对象(可以在不同地方通过名称获取同一实例)const conditionVariableRequest: ArkTSUtils.locks.ConditionVariable =ArkTSUtils.locks.ConditionVariable.request("Request1");// 将实例conditionVariableRequest传递给wait线程taskpool.execute(wait, conditionVariableRequest);// 将实例conditionVariableRequest传递给notifyAll线程,唤醒wait线程,日志输出"TaskPool Thread Wait: success"taskpool.execute(notifyAll, conditionVariableRequest);// 将实例conditionVariableRequest传递给waitFor线程taskpool.execute(waitFor, conditionVariableRequest);// 将实例conditionVariableRequest传递给notifyOne线程,唤醒waitFor线程,日志输出"TaskPool Thread WaitFor: success"taskpool.execute(notifyOne, conditionVariableRequest);})}.width('100%')}.height('100%')}
}

ASON解析与生成

ASON工具与JS提供的JSON工具类似,JSON用于进行JS对象的序列化(stringify)、反序列化(parse)。ASON则提供了Sendable对象的序列化、反序列化**能力。

共享容器

ArkTS共享容器在多个并发实例间传递时,默认采用引用传递,允许多个并发实例操作同一容器实例。此外,还支持拷贝传递,即每个并发实例拥有独立的ArkTS容器实例。

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

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

import { ArkTSUtils, collections, taskpool } from '@kit.ArkTS';@Concurrent
async function add(arr: collections.Array<number>, lock: ArkTSUtils.locks.AsyncLock) {await lock.lockAsync(() => {  // 如果不添加异步锁,任务会因为数据竞争冲突,导致抛异常失败arr[0]++;})
}@Entry
@Component
struct 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;let num = count;while (num--) {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%')}
}

共享模块

共享模块进程内只会加载一次的模块,使用"use shared"这一指令来标记一个模块是否为共享模块。

非共享模块同一线程内只加载一次,而在不同线程中会多次加载,每个线程都会生成新的模块对象。因此,目前只能使用共享模块实现进程单例。

  • "use shared"需要与"use strict"一样写在ArkTS文件顶层,写在import语句之后其他语句之前。

  • 共享属性不具备传递性。非共享模块A即使引入了共享模块B,也不会因此变成共享模块。

  • 共享模块只支持ets文件。

  • 共享模块内不允许使用side-effects-import。

    // 不允许使用side-effects-import,编译报错
    import "./test";
    "use shared"
    
  • 共享模块在同一进程内仅加载一次,可在不同线程间共享

  • 共享模块加载时,导入的非共享模块不会立即加载。在共享模块内访问依赖的非共享模块导出变量时,当前线程会懒加载对应的非共享模块。非共享模块在线程间隔离,不同线程访问时会进行一次懒加载。

  • 由于side-effects-import不涉及导出变量,因此不会被加载,也不受支持。

  • 共享模块导出的变量必须是可共享对象

  • 共享模块在并发实例间可共享,因此导出的所有对象必须是可共享的。

  • 共享模块不支持re-export写法。

  • 共享模块可以引用其他共享模块或非共享模块,引用和被引用场景没有限制。

  • 仅支持使用静态加载、napi_load_module或napi_load_module_with_info加载共享模块。

Sendable对象冻结

Sendable对象支持冻结操作。冻结后,对象变为只读,不能修改属性。因此,多个并发实例间访问时无需加锁。可以通过调用Object.freeze接口冻结对象。

  1. 提供ts文件封装Object.freeze方法。

    // helper.ts
    export function freezeObj(obj: any) {Object.freeze(obj);
    }
    
  2. 调用freeze方法冻结对象,然后将其发送到子线程。

    // Index.ets
    import { freezeObj } from './helper';
    import { worker } from '@kit.ArkTS';@Sendable
    export class GlobalConfig {// 一些配置属性与方法init() {// 初始化相关逻辑freezeObj(this); // 初始化完成后冻结当前对象}
    }@Entry
    @Component
    struct Index {build() {Column() {Text("Sendable freezeObj Test").id('HelloWorld').fontSize(50).fontWeight(FontWeight.Bold).onClick(() => {let gConfig = new GlobalConfig();gConfig.init();const workerInstance = new worker.ThreadWorker('entry/ets/workers/Worker.ets', { name: "Worker1" });workerInstance.postMessage(gConfig);})}.height('100%').width('100%')}
    }
    
  3. 子线程直接操作对象,不加锁。

    // Worker.ets
    import { ErrorEvent, MessageEvents, ThreadWorkerGlobalScope, worker } from '@kit.ArkTS';
    import { GlobalConfig } from '../pages/Index';const workerPort: ThreadWorkerGlobalScope = worker.workerPort;
    workerPort.onmessage = (e: MessageEvents) => {let gConfig: GlobalConfig = e.data;// 使用gConfig对象
    }
    
http://www.dtcms.com/a/503332.html

相关文章:

  • 产品经理做网站东莞网站搭建
  • vue3中的watch使用
  • SQL Server安全配置全面检查与优化方案
  • 唐山市城乡建设局网站哪个网站做的系统好用吗
  • 包头市建设厅官方网站开网店详细步骤流程
  • 什么是前端、后端与全栈开发,Qt属于什么?
  • Solidity 合约超限问题及优化策略:以 FHEFactory 为例
  • 第一届贵州理工校赛--ez-uploadez-upload-plus
  • 聊聊 Unity(小白专享、C# 小程序 之 联机对战)
  • ava编辑一个小程序操作教程分享一下C++
  • Java Web 程序在 Linux 上的部署
  • HTTP Client/Server 实践:cpp-httplib使用
  • 项目招商网站大全河北智慧团建网站
  • 量化交易的开源框架
  • 【Linux系统编程】4. Linux权限
  • 个人主页网站制作免费融资平台哪家好
  • week6
  • ZigBee中的many-to-one和link status(3)
  • 大型网站多少钱佳源房地产最新消息
  • Linux Bash(一)
  • 【Redis】哨兵与对脑裂的情况分析
  • 49.词向量:把文字变成数字
  • 【pulldown-cmark】创建自定义分支
  • python 网站开发流程图网站首页被k还有救吗
  • TsingtaoAI受邀参加HICOOL2025全球创业者峰会项目对接会
  • windows10激活解决办法
  • 学习建网站玩网站建设学习包装设计需要哪些信息
  • 【图像处理】rgb和srgb
  • 如何撰写网站建设方案海口网站开发制作
  • 查找成绩(向量实现)