• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# ArrayBuffer对象
2
3ArrayBuffer由两部分组成:底层存储数据的Native内存区域,以及封装操作的JS对象壳,该JS对象壳被分配在虚拟机本地堆(LocalHeap)。跨线程传递时,JS对象壳需要经过序列化与反序列化拷贝传递,Native内存区域则有两种传递方式:拷贝和转移。
4
5采用拷贝方式(递归遍历),传输后两个线程可以独立访问ArrayBuffer。通信过程如下图所示:
6
7![copy_transfer](figures/copy_transfer.png)
8
9采用转移方式,传输后原线程将无法使用此ArrayBuffer对象。跨线程时只需重建JS壳,Native内存无需拷贝,效率更高。通信过程如下图所示:
10
11![transfer](figures/transfer.png)
12
13ArrayBuffer可以用来表示图片等资源,在应用开发中,处理图片(如调整亮度、饱和度、大小等)时,为了避免阻塞UI主线程,可以将图片传递到子线程中进行处理。转移方式性能更高,但原线程无法再访问ArrayBuffer对象。如果两个线程都需要访问该对象,建议采用拷贝方式。否则,建议采用转移方式,以提升性能。
14
15下面将分别通过拷贝和转移的方式,将图片传递到子线程中。
16
17## ArrayBuffer拷贝传输方式
18
19在ArkTS中,TaskPool传递ArrayBuffer数据时,默认使用转移方式,通过调用setTransferList()接口,可以指定部分数据的传递方式为转移方式,而其他部分数据可以切换为拷贝方式。
20
21首先,实现一个处理ArrayBuffer的接口,该接口在Task中执行。
22
23然后,通过拷贝方式将ArrayBuffer数据传递到Task中,并处理。
24
25最后,UI主线程接收到Task执行完毕后返回的ArrayBuffer数据,拼接并展示。
26
27```ts
28// Index.ets
29import { taskpool } from '@kit.ArkTS';
30import { BusinessError } from '@kit.BasicServicesKit';
31
32@Concurrent
33function adjustImageValue(arrayBuffer: ArrayBuffer): ArrayBuffer {
34  // 对arrayBuffer进行操作
35  return arrayBuffer;  // 返回值默认转移
36}
37
38function createImageTask(arrayBuffer: ArrayBuffer, isParamsByTransfer: boolean): taskpool.Task {
39  let task: taskpool.Task = new taskpool.Task(adjustImageValue, arrayBuffer);
40  if (!isParamsByTransfer) { // 是否使用转移方式
41    // 传递空数组[],全部arrayBuffer参数传递均采用拷贝方式
42    task.setTransferList([]);
43  }
44  return task;
45}
46
47@Entry
48@Component
49struct Index {
50  @State message: string = 'Hello World';
51
52  build() {
53    RelativeContainer() {
54      Text(this.message)
55        .id('HelloWorld')
56        .fontSize(50)
57        .fontWeight(FontWeight.Bold)
58        .alignRules({
59          center: { anchor: '__container__', align: VerticalAlign.Center },
60          middle: { anchor: '__container__', align: HorizontalAlign.Center }
61        })
62        .onClick(() => {
63          let taskNum = 4;
64          let arrayBuffer = new ArrayBuffer(1024 * 1024);
65          let taskPoolGroup = new taskpool.TaskGroup();
66          // 创建taskNum个Task
67          for (let i: number = 0; i < taskNum; i++) {
68            let arrayBufferSlice: ArrayBuffer = arrayBuffer.slice(arrayBuffer.byteLength / taskNum * i, arrayBuffer.byteLength / taskNum * (i + 1));
69            // 使用拷贝方式传入ArrayBuffer,所以isParamsByTransfer为false
70            taskPoolGroup.addTask(createImageTask(arrayBufferSlice, false));
71          }
72          // 执行Task
73          taskpool.execute(taskPoolGroup).then((data) => {
74            // 返回结果,对数组拼接,获得最终结果
75          }).catch((e: BusinessError) => {
76            console.error(e.message);
77          })
78        })
79    }
80    .height('100%')
81    .width('100%')
82  }
83}
84```
85
86## ArrayBuffer转移传输方式
87
88在TaskPool中,传递ArrayBuffer数据时默认使用转移方式,原线程将无法再使用已传输给子线程的ArrayBuffer。在上文示例的基础上去除task.setTransferList接口调用,即在createImageTask的第二个参数传入true,就可以实现转移方式的传输。
89