鸿蒙多线程开发——线程间数据通信对象03(sendable)
1、简 介
在传统JS引擎上,对象的并发通信开销的优化方式只有一种,就是把实现下沉到Native侧,通过Transferable对象的转移或共享方式降低并发通信开销。而开发者仍然还有大量对象并发通信的诉求,这个问题在业界的JS引擎实现上并没有得到解决。
ArkTS提供了Sendable对象类型,在并发通信时支持通过引用传递来解决上述问题。
Sendable对象为可共享的,其跨线程前后指向同一个JS对象,如果其包含了JS或者Native内容,均可以直接共享,如果底层是Native实现的,则需要考虑线程安全性。通信过程如下图所示:

与其它ArkTS对象不一样的是,符合Sendable协议的数据对象在运行时必须是类型固定的对象。
当多个并发实例尝试同时更新Sendable数据时,会发生数据竞争。因此,ArkTS提供了异步锁的机制来避免不同并发实例间的数据竞争。同时,还可以通过对象冻结接口冻结对象,将其变为只读对象,就可以不用考虑数据的竞争问题。
Sendable对象提供了并发实例间高效的通信效率,即引用传递的能力,一般适用于开发者自定义大对象需要线程间通信的场景,例如子线程读取数据库的数据返回主线程。
2、Sendable对象类型基础概念
2.1、Sendable协议
Sendable协议定义了ArkTS的可共享对象体系及其规格约束。符合Sendable协议的数据(以下简称Sendable对象)可以在ArkTS并发实例间传递。
默认情况下,Sendable数据在ArkTS并发实例间(包括主线程、TaskPool、Worker线程)传递的行为是引用传递。同时,ArkTS也支持Sendable数据在ArkTS并发实例间拷贝传递。
2.2、ISendable接口
在ArkTS语言基础库@arkts.lang中引入了interface ISendable,没有任何必须的方法或属性。ISendable是所有Sendable类型(除了null和undefined)的父类型。ISendable主要用在开发者自定义Sendable数据结构的场景中。类装饰器@Sendable装饰器是implement ISendable的语法糖。
2.3、@Sendable装饰器
用于声明并校验Sendable类以及Sendable函数。有以下需要注意的使用限制:
-
Sendable class只能继承Sendable class,普通Class不可以继承Sendable class。
-
装饰的对象内的属性类型限制
1. 支持string、number、boolean、bigint、null、undefined、Sendable class、collections.Array、collections.Map、collections.Set、ArkTSUtils.locks.AsyncLock。
2. 禁止使用闭包变量。
3. 不支持通过#定义私有属性,需用private。
4. 不支持计算属性。
-
成员属性必须显式初始化。成员属性不能跟感叹号。
-
允许使用local变量、入参和通过import引入的变量。禁止使用闭包变量,定义在顶层的Sendable class和Sendable function除外。
-
不支持增加属性、不支持删除属性、允许修改属性,修改前后属性的类型必须一致、不支持修改方法。
Sendable类使用示例如下:
@Sendableclass SendableTestClass {desc: string = "sendable: this is SendableTestClass ";num: number = 5;printName() {console.info("sendable: SendableTestClass desc is: " + this.desc);}get getNum(): number {return this.num;}}
Sendable函数使用示例如下:
@Sendabletype SendableFuncType = () => void;@Sendableclass TopLevelSendableClass {num: number = 1;PrintNum() {console.info("Top level sendable class");}}@Sendablefunction TopLevelSendableFunction() {console.info("Top level sendable function");}@Sendablefunction SendableTestFunction() {const topClass = new TopLevelSendableClass(); // 顶层sendable classtopClass.PrintNum();TopLevelSendableFunction(); // 顶层sendable functionconsole.info("Sendable test function");}@Sendableclass SendableTestClass {constructor(func: SendableFuncType) {this.callback = func;}callback: SendableFuncType; // 顶层sendable functionCallSendableFunc() {SendableTestFunction(); // 顶层sendable function}}let sendableClass = new SendableTestClass(SendableTestFunction);sendableClass.callback();sendableClass.CallSendableFunc();
2.4、Sendable支持的数据类型
-
所有的ArkTS基本数据类型:boolean, number, string, bigint, null, undefined。
-
ArkTS语言标准库中定义的容器类型数据(须显式引入@arkts.collections)。
-
ArkTS语言标准库中定义的异步锁对象(须显式引入@arkts.utils)。
-
继承了ISendable的interface。
-
标注了@Sendable装饰器的class。
-
标注了@Sendable装饰器的function。
-
接入Sendable的系统对象。
-
共享用户首选项
-
可共享的色彩管理
-
基于Sendable对象的图片处理
-
资源管理
-
SendableContext对象管理
-
-
元素均为Sendable类型的union type数据。
|
2.5、Sendable的实现原理
为了实现Sendable数据在不同并发实例间的引用传递,Sendable共享对象会分配在共享堆中,以实现跨并发实例的内存共享。
共享堆(SharedHeap)是进程级别的堆空间,与虚拟机本地堆(LocalHeap)不同的是,LocalHeap只能被单个并发实例访问,而SharedHeap可以被所有线程访问。一个Sendable共享对象的跨线程行为是引用传递。因此,Sendable可能被多个并发实例引用,判断Sendable共享对象是否存活,取决于所有并发实例的对象是否存在对此Sendable共享对象的引用。
SharedHeap与LocalHeap关系图

各个并发实例间的LocalHeap是隔离的,SharedHeap是进程级别的堆,可以被所有的并发实例引用。但是SharedHeap不能引用LocalHeap中的对象。
3、Sendable使用场景
Sendable对象可以在不同并发实例间通过引用传递。通过引用传递方式传输对象相比序列化方式更加高效,同时不会丢失class上携带的成员方法。因此,Sendable主要可以解决两个场景的问题:
-
跨并发实例传输大数据(例如可能达到100KB以上的数据)。
-
跨并发实例传递带方法的class实例对象。
3.1、跨并发实例传输大数据场景
由于跨并发实例序列化的开销随着数据量线性增长,因此当传输数据量较大时(100KB数据大约1ms传输耗时),跨并发实例的拷贝开销大,影响应用性能。引用传递方式传输对象可提升性能。示例如下:
// Index.etsimport { taskpool } from '@kit.ArkTS';import { testTypeA, testTypeB, Test } from './sendable';import { BusinessError, emitter } from '@kit.BasicServicesKit';// 在并发函数中模拟数据处理@Concurrentasync function taskFunc(obj: Test) {console.info("test task res1 is: " + obj.data1.name + " res2 is: " + obj.data2.name);}async function test() {// 使用taskpool传递数据let a: testTypeA = new testTypeA("testTypeA");let b: testTypeB = new testTypeB("testTypeB");let obj: Test = new Test(a, b);let task: taskpool.Task = new taskpool.Task(taskFunc, obj);await taskpool.execute(task);}@Concurrentfunction SensorListener() {// 监听逻辑// ...}@Entry@Componentstruct Index {build() {Column() {Text("Listener task").id('HelloWorld').fontSize(50).fontWeight(FontWeight.Bold).onClick(() => {let sensorTask = new taskpool.LongTask(SensorListener);emitter.on({ eventId: 0 }, (data) => {// Do something hereconsole.info(`Receive ACCELEROMETER data: {${data.data?.x}, ${data.data?.y}, ${data.data?.z}`);});taskpool.execute(sensorTask).then(() => {console.info("Add listener of ACCELEROMETER success");}).catch((e: BusinessError) => {// Process error})})Text("Data processing task").id('HelloWorld').fontSize(50).fontWeight(FontWeight.Bold).onClick(() => {test();})}.height('100%').width('100%')}}// sendable.ets// 将数据量较大的数据在Sendable class中组装@Sendableexport class testTypeA {name: string = "A";constructor(name: string) {this.name = name;}}@Sendableexport class testTypeB {name: string = "B";constructor(name: string) {this.name = name;}}@Sendableexport class Test {data1: testTypeA;data2: testTypeB;constructor(arg1: testTypeA, arg2: testTypeB) {this.data1 = arg1;this.data2 = arg2;}}
3.2、跨并发实例传递带方法的class实例对象
由于序列化传输实例对象时会丢失方法,在必须调用实例方法的场景中,需使用引用传递方式进行开发。在数据处理过程中有需要解析的数据,可使用ASON工具进行数据解析。示例如下:
// Index.etsimport { taskpool, ArkTSUtils } from '@kit.ArkTS';import { SendableTestClass, ISendable } from './sendable';// 在并发函数中模拟数据处理@Concurrentasync function taskFunc(sendableObj: SendableTestClass) {console.info("SendableTestClass: name is: " + sendableObj.printName() + ", age is: " + sendableObj.printAge() + ", sex is: " + sendableObj.printSex());sendableObj.setAge(28);console.info("SendableTestClass: age is: " + sendableObj.printAge());// 解析sendableObj.arr数据生成JSON字符串let str = ArkTSUtils.ASON.stringify(sendableObj.arr);console.info("SendableTestClass: str is: " + str);// 解析该数据并生成ISendable数据let jsonStr = '{"name": "Alexa", "age": 23, "sex": "female"}';let obj = ArkTSUtils.ASON.parse(jsonStr) as ISendable;console.info("SendableTestClass: type is: " + typeof obj);console.info("SendableTestClass: name is: " + (obj as object)?.["name"]); // 输出: 'Alexa'console.info("SendableTestClass: age is: " + (obj as object)?.["age"]); // 输出: 23console.info("SendableTestClass: sex is: " + (obj as object)?.["sex"]); // 输出: 'female'}async function test() {// 使用taskpool传递数据let obj: SendableTestClass = new SendableTestClass();let task: taskpool.Task = new taskpool.Task(taskFunc, obj);await taskpool.execute(task);}@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(() => {test();})}.height('100%').width('100%')}}// sendable.ets// 定义模拟类Test,模仿开发过程中需传递带方法的classimport { lang, collections } from '@kit.ArkTS'export type ISendable = lang.ISendable;@Sendableexport class SendableTestClass {name: string = 'John';age: number = 20;sex: string = "man";arr: collections.Array<number> = new collections.Array<number>(1, 2, 3);constructor() {}setAge(age: number) : void {this.age = age;}printName(): string {return this.name;}printAge(): number {return this.age;}printSex(): string {return this.sex;}}
相关文章:
鸿蒙多线程开发——线程间数据通信对象03(sendable)
1、简 介 在传统JS引擎上,对象的并发通信开销的优化方式只有一种,就是把实现下沉到Native侧,通过Transferable对象的转移或共享方式降低并发通信开销。而开发者仍然还有大量对象并发通信的诉求,这个问题在业界的JS引擎实现上并没…...
linux从0到1——shell编程7
声明! 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无关&a…...
自主研发,基于PHP+ vue2+element+ laravel8+ mysql5.7+ vscode开发的不良事件管理系统源码,不良事件管理系统源码
不良事件上报系统源码,不良事件管理系统源码,PHP源码 不良事件上报系统通过 “事前的人员知识培训管理和制度落地促进”、“事中的事件上报和跟进处理”、 以及 “事后的原因分析和工作持续优化”,结合预存上百套已正在使用的模板࿰…...
【海思Hi3519DV500】双目网络相机套板硬件规划方案
Hi3519DV500双目网络相机套板是针对该芯片设计的一款 IP 编码板 PCBA,硬件接口支持双目sensor 接入,SDIO3.0 接口、USB2.0、USB3.0、UART 接口以及丰富的 IO 扩展应用,可根据各种使用场景设计相应扩展板,丰富外围接口,…...
【电源专题】BUCK电源SW电压的平均值为什么等于输出电压?
在Buck电源测试过程中,我们会去测试SW开关节点的波形。那么从SW波形中我们能看出什么呢? 首先查看SW波形一般会看SW频率,通过SW波形的频率知道目前芯片的运行状态是什么。比如PSM还是PWM模式。 此外,还会看SW波形的占空比,通过占空比我们可以知道目前输出的状态是怎么样的…...
SpringCloud Gateway转发请求到同一个服务的不同端口
SpringCloud Gateway默认不支持将请求路由到一个服务的多个端口 本文将结合Gateway的处理流程,提供一些解决思路 需求背景 公司有一个IM项目,对外暴露了两个端口8081和8082,8081是springboot启动使用的端口,对外提供一些http接口…...
【模块一】kubernetes容器编排进阶实战之pod的调度流程,pause容器及init容器
pod的调度流程及常见状态 pod的调度流 pod的常见状态 Unschedulable:#Pod不能被调度,kube-scheduler没有匹配到合适的node节点 PodScheduled:#pod正处于调度中,在kube-scheduler刚开始调度的时候,还没有将pod分配…...
PySpark3:pyspark.sql.functions常见的60个函数
目录 一、常见的60个函数 1、col 2、lit 3、sum 4、avg/mean 5、count 6、max 7、min 8、concat 9、substring 10、lower 11、upper 12、trim 13、ltrim 14、rtrim 15、split 16、explode 17、collect_list 18、collect_set 19、asc 20、desc 21、when 2…...
Python操作neo4j库py2neo使用之创建和查询(二)
Python操作neo4j库py2neo使用之创建和查询(二) py2neo 创建操作 1、连接数据库 from py2neo import Graph graph Graph("bolt://100.100.20.55:7687", auth(user, pwd), nameneo4j)2、创建Node from py2neo import Node, Subgraph # 创建…...
力扣11.23
1964. 找出到每个位置为止最长的有效障碍赛跑路线 你打算构建一些障碍赛跑路线。给你一个 下标从 0 开始 的整数数组 obstacles ,数组长度为 n ,其中 obstacles[i] 表示第 i 个障碍的高度。 对于每个介于 0 和 n - 1 之间(包含 0 和 n - 1&…...
golang实现TCP服务器与客户端的断线自动重连功能
1.服务端 2.客户端 生成服务端口程序: 生成客户端程序: 测试断线重连: 初始连接成功...
数据结构 (6)栈的应用举例
1. 递归调用 递归函数在执行时,会将每一层的函数调用信息(包括局部变量、参数和返回地址)存储在栈中。当递归函数返回时,这些信息会从栈中弹出,以便恢复之前的执行状态。栈的后进先出(LIFO)特性…...
谁的年龄最小(结构体专题)
题目描述 设计一个结构体类型,包含姓名、出生日期。其中出生日期又包含年、月、日三部分信息。输入n个好友的信息,输出年龄最小的好友的姓名和出生日期。 输入描述 首先输入一个整数n(1<n<10),表示好友人数,然后输入n行&…...
【论文笔记】LLaVA-KD: A Framework of Distilling Multimodal Large Language Models
Abstract 大语言模型(Large Language Models, LLM)的成功,使得研究者为了统一视觉和语言的理解去探索多模态大预言模型(Multimodal Large Language Models, MLLM)。 但是MLLM庞大的模型和复杂的计算使其很难应用在资源受限的环境,小型MLLM(s-MLLM)的表现…...
M|大脑越狱
rating: 7.0 豆瓣: 7.6 上映时间: “2015” 类型: M悬疑 导演: 约瑟夫怀特 Joseph White 主演: 亚历山大欧文 Alexander Owen爱德华富兰克林 Edward Franklin 国家/地区: 英国 片长/分钟: 20分钟 M|大脑越狱 想法不错,但是逻辑比较一般。属于…...
数据库编程(sqlite3)
一:数据库分类 常用的数据库 大型数据库 :Oracle商业、多平台、关系型数据库功能最强大、最复杂、市场占比最高的商业数据库 中型数据库 :Server是微软开发的数据库产品,主要支持windows平台 小型数据库 : mySQL是一个小型关系型…...
【C语言】关键字详解
【C语言】关键字详解 文章目录 [TOC](文章目录) 前言一、char1.定义字符串类型2.定义字符类型 二、short三、int四、long五、signed六、unsigned七、float八、double九、struct、union、enum十、void1.void用于函数声明,没有返回值的函数,其类型为 void。…...
什么是计算机网络
什么是计算机网络? 计算机网络的定义计算机网络的分类按覆盖范围分类按拓扑结构分类按通信传输介质分类按信号频带占用方式分类 计算机网络的功能信息交换资源共享分布式处理 计算机网络的组成计算机网络的定义计算机网络的分类按覆盖范围分类按拓扑结构分类按通信传…...
【大数据学习 | Spark-Core】Spark的分区器(HashPartitioner和RangePartitioner)
之前学过的kv类型上面的算子 groupby groupByKey reduceBykey sortBy sortByKey join[cogroup left inner right] shuffle的 mapValues keys values flatMapValues 普通算子,管道形式的算子 shuffle的过程是因为数据产生了打乱重分,分组、排序、join等…...
CSS3_BFC(十二)
BFC MDN对BFC的解释:块格式化上下文(Block Formating Context, BFC)是web页面的可视CSS渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。 1、开启BFC flow-root对内容的影响是最低的&am…...
3个步骤彻底解决WSA安装失败问题:从错误代码到完美运行
3个步骤彻底解决WSA安装失败问题:从错误代码到完美运行 【免费下载链接】WSABuilds Run Windows Subsystem For Android on your Windows 10 and Windows 11 PC using prebuilt binaries with Google Play Store (MindTheGapps) and/or Magisk or KernelSU (root so…...
输电线路在线监测系统|架空线路安全运行的“第一道防线“!
输电线路微气象监测站是专为高压输电线路、电网廊道、杆塔运维量身打造的专利级一体化微气象智能监测设备。依托双专利超声波探测技术、六要素集成传感架构、无启动风速高精测量、智能抗干扰稳控系统,实现输电线路沿线气象24小时全自动捕捉、动态实时监测、大风风险…...
【独家首发】DeepSeek官方未公开的集成测试Checklist(含23项生产环境准入阈值与压测基线)
更多请点击: https://codechina.net 第一章:DeepSeek集成测试方案 DeepSeek模型的集成测试需覆盖推理服务稳定性、多模态输入兼容性、上下文长度边界及API协议一致性四大核心维度。测试环境基于Kubernetes集群部署,采用PrometheusGrafana监控…...
用Playwright自动化测试工具,5分钟搞定网站短信验证码接口的批量测试
用Playwright实现短信验证码接口的自动化测试实战指南短信验证码作为现代Web应用的核心安全组件,其稳定性和防护能力直接影响用户体验和系统安全。根据2023年DevOps状态报告,超过60%的线上身份验证故障源于短信服务接口的异常。本文将带你用Playwright这…...
告别网盘龟速下载!这款神器让你轻松获取9大网盘直链,下载效率提升300%
告别网盘龟速下载!这款神器让你轻松获取9大网盘直链,下载效率提升300% 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里…...
机器学习优化多浴模型参数结合HEOM计算分子红外光谱
1. 项目概述:当机器学习遇见分子光谱模拟在分子光谱模拟这个领域里,我们这些做计算化学和理论光谱的人,常年都在和一堆复杂的方程和庞大的计算量作斗争。核心目标很明确:我们想从原子和分子的微观运动出发,精准地预测出…...
淘金币自动化脚本终极指南:5分钟解放双手,轻松获取每日奖励
淘金币自动化脚本终极指南:5分钟解放双手,轻松获取每日奖励 【免费下载链接】taojinbi 淘宝淘金币自动执行脚本,包含蚂蚁森林收取能量,芭芭农场全任务,解放你的双手 项目地址: https://gitcode.com/gh_mirrors/ta/ta…...
Spring Boot项目里,我是怎么把文心一言API集成进去的(附完整代码)
Spring Boot项目中集成文心一言API的实战指南 最近在开发一个需要AI对话功能的Spring Boot应用时,我选择了百度的文心一言作为后端引擎。整个过程从申请API权限到最终实现流式响应,踩了不少坑也积累了一些经验。本文将分享如何在Spring Boot项目中优雅地…...
告别截图!用UE4/UE5的WebUI插件,把实时数据大屏“搬”进数字孪生场景
告别截图!用UE4/UE5的WebUI插件实现实时数据大屏与数字孪生场景的无缝融合在工业仿真和智慧城市领域,数据可视化大屏与三维场景的联动一直是技术难点。传统解决方案往往依赖静态截图或视频播放,导致数据延迟、交互缺失。本文将深入探讨如何通…...
华硕笔记本性能优化终极指南:如何用G-Helper替代Armoury Crate提升体验
华硕笔记本性能优化终极指南:如何用G-Helper替代Armoury Crate提升体验 【免费下载链接】g-helper Lightweight Armoury Crate alternative for Asus laptops with nearly the same functionality. Works with ROG Zephyrus, Flow, TUF, Strix, Scar, ProArt, Vivob…...
