往期知识点整理
- 鸿蒙(HarmonyOS)北向开发知识点记录~
- 鸿蒙(HarmonyOS)应用开发之性能优化实战-组件复用
- 鸿蒙(HarmonyOS)应用性能优化实战-组件复用四板斧
- 鸿蒙(HarmonyOS)应用开发性能优化实战-WaterFlow高性能开发
- 鸿蒙(HarmonyOS)性能优化实战-Swiper高性能开发
- 鸿蒙(HarmonyOS)性能优化实战-合理使用renderGroup
- 鸿蒙(HarmonyOS)性能优化实战-减少动画丢帧
- 鸿蒙(HarmonyOS)性能优化实战-多线程共享内存
- 持续更新中……
概述
在应用开发中,为了避免主线程阻塞,提高应用性能,需要将一些耗时操作放在子线程中执行。此时,子线程就需要访问主线程中的数据。ArkTS采用了基于消息通信的Actor并发模型,具有内存隔离的特性,所以跨线程传输数据时需要将数据序列化,但是AkrTS支持通过可共享对象SharedArrayBuffer实现直接的共享内存。
在开发应用时,如果遇到数据量较大,并且需要多个线程同时操作的情况,推荐使用SharedArrayBuffer共享内存,可以减少数据在线程间传递时需要复制和序列化的额外开销。比如,音视频解码播放、多个线程同时读取写入文件等场景。由于内存是共享的,所以在多个线程同时操作同一块内存时,可能会引起数据的紊乱,这时就需要使用锁来确保数据操作的有序性。本文将基于此具体展开说明。关于多线程的使用和原理,本文将不再详细讲述。
工作原理
可共享对象SharedArrayBuffer,是拥有固定长度的原始二进制数据缓冲区,可以存储任何类型的数据,包括数字、字符串等。它支持在多线程之间传递,传递之后的SharedArrayBuffer对象和原始的SharedArrayBuffer对象可以指向同一块内存,进而达到共享内存的目的。SharedArrayBuffer对象存储的数据在子线程中被修改时,需要通过原子操作保证其同步性,即下个操作开始之前务必需要保证上个操作已经结束。下面将通过示例说明原子操作保证同步性的必要性。
非原子操作
......
// 非原子操作,进行10000次++
@Concurrent
function normalProcess(int32Array: Int32Array) {
for (let i = 0; i < 10000; i++) {
int32Array[0]++;
}
}
// 原子操作,进行10000次++
@Concurrent
function atomicsProcess(int32Array: Int32Array) {
for (let i = 0; i < 10000; i++) {
Atomics.add(int32Array, 0, 1);
}
}
......
@State result: string = "计算结果:";
private taskNum: number = 2;
private scroller: Scroller = new Scroller();
......
Button("非原子操作")
.width("80%")
.fontSize(30)
.fontWeight(FontWeight.Bold)
.margin({
top: 30 })
.onClick(async () => {
this.sharedArrayBufferUsage(false);
})
Scroll(this.scroller) {
Column() {
Text(this.result)
.width("80%")
.fontSize(30)
.fontWeight(FontWeight.Bold)
.fontColor(Color.Blue)
}
}.height("60%")
.margin({
top: 30 })
......
// 根据传入的值isAtomics判断是否使用原子操作
sharedArrayBufferUsage(isAtomics: boolean) {
// 创建长度为4的SharedArrayBuffer对象
let sab: SharedArrayBuffer = new SharedArrayBuffer(4);
// 由于SharedArrayBuffer是原始二进制数据缓冲区,无法直接使用,所以这里转换为Int32Array类型进行后续操作
let int32Array: Int32Array = new Int32Array(sab);
int32Array[0