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类使用示例如下:
@Sendable
class 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函数使用示例如下:
@Sendable
type SendableFuncType = () => void;
@Sendable
class TopLevelSendableClass {