2
2
3
3
` ArrayBuffer ` 对象、` TypedArray ` 视图和` DataView ` 视图是 JavaScript 操作二进制数据的一个接口。这些对象早就存在,属于独立的规格(2011年2月发布),ES6 将它们纳入了 ECMAScript 规格,并且增加了新的方法。它们都是以数组的语法处理二进制数据,所以统称为二进制数组。
4
4
5
- 这个接口的原始设计目的,与 WebGL 项目有关。所谓WebGL ,就是指浏览器与显卡之间的通信接口,为了满足 JavaScript 与显卡之间大量的、实时的数据交换,它们之间的数据通信必须是二进制的,而不能是传统的文本格式。文本格式传递一个32位整数,两端的 JavaScript 脚本与显卡都要进行格式转化,将非常耗时。这时要是存在一种机制,可以像 C 语言那样,直接操作字节,将4个字节的32位整数,以二进制形式原封不动地送入显卡,脚本的性能就会大幅提升。
5
+ 这个接口的原始设计目的,与 WebGL 项目有关。所谓 WebGL ,就是指浏览器与显卡之间的通信接口,为了满足 JavaScript 与显卡之间大量的、实时的数据交换,它们之间的数据通信必须是二进制的,而不能是传统的文本格式。文本格式传递一个32位整数,两端的 JavaScript 脚本与显卡都要进行格式转化,将非常耗时。这时要是存在一种机制,可以像 C 语言那样,直接操作字节,将4个字节的32位整数,以二进制形式原封不动地送入显卡,脚本的性能就会大幅提升。
6
6
7
- 二进制数组就是在这种背景下诞生的。它很像C语言的数组,允许开发者以数组下标的形式,直接操作内存,大大增强了JavaScript处理二进制数据的能力,使得开发者有可能通过JavaScript与操作系统的原生接口进行二进制通信 。
7
+ 二进制数组就是在这种背景下诞生的。它很像C语言的数组,允许开发者以数组下标的形式,直接操作内存,大大增强了 JavaScript 处理二进制数据的能力,使得开发者有可能通过 JavaScript 与操作系统的原生接口进行二进制通信 。
8
8
9
9
二进制数组由三类对象组成。
10
10
11
11
** (1)` ArrayBuffer ` 对象** :代表内存之中的一段二进制数据,可以通过“视图”进行操作。“视图”部署了数组接口,这意味着,可以用数组的方法操作内存。
12
12
13
- ** (2)TypedArray视图 ** :共包括9种类型的视图,比如` Uint8Array ` (无符号8位整数)数组视图, ` Int16Array ` (16位整数)数组视图, ` Float32Array ` (32位浮点数)数组视图等等。
13
+ ** (2)` TypedArray ` 视图 ** :共包括9种类型的视图,比如` Uint8Array ` (无符号8位整数)数组视图, ` Int16Array ` (16位整数)数组视图, ` Float32Array ` (32位浮点数)数组视图等等。
14
14
15
15
** (3)` DataView ` 视图** :可以自定义复合格式的视图,比如第一个字节是 Uint8(无符号8位整数)、第二、三个字节是 Int16(16位整数)、第四个字节开始是 Float32(32位浮点数)等等,此外还可以自定义字节序。
16
16
@@ -1041,7 +1041,7 @@ onmessage = function (ev) {
1041
1041
1042
1042
共享内存也可以在 Worker 线程创建,发给主线程。
1043
1043
1044
- ` SharedArrayBuffer ` 与` SharedArray ` 一样,本身是无法读写 ,必须在上面建立视图,然后通过视图读写。
1044
+ ` SharedArrayBuffer ` 与` ArrayBuffer ` 一样,本身是无法读写的 ,必须在上面建立视图,然后通过视图读写。
1045
1045
1046
1046
``` javascript
1047
1047
// 分配 10 万个 32 位整数占据的内存空间
@@ -1075,7 +1075,7 @@ onmessage = function (ev) {
1075
1075
1076
1076
## Atomics 对象
1077
1077
1078
- 多线程共享内存,最大的问题就是如何防止两个线程同时修改某个地址,或者说,当一个线程修改共享内存以后,必须有一个机制让其他线程同步。SharedArrayBuffer API 提供` Atomics ` 对象,保证所有共享内存的操作都是“原子性”的,并且可以在所有进程内同步 。
1078
+ 多线程共享内存,最大的问题就是如何防止两个线程同时修改某个地址,或者说,当一个线程修改共享内存以后,必须有一个机制让其他线程同步。SharedArrayBuffer API 提供` Atomics ` 对象,保证所有共享内存的操作都是“原子性”的,并且可以在所有线程内同步 。
1079
1079
1080
1080
什么叫“原子性操作”呢?现代编程语言中,一条普通的命令被编译器处理以后,会变成多条机器指令。如果是单线程运行,这是没有问题的;多线程环境并且共享内存时,就会出问题,因为这一组机器指令的运行期间,可能会插入其他线程的指令,从而导致运行结果出错。请看下面的例子。
1081
1081
@@ -1092,7 +1092,7 @@ console.log(ia[42]);
1092
1092
// 191
1093
1093
```
1094
1094
1095
- 上面代码中,主线程的原始顺序是先对42号位置赋值,再对37号位置赋值。但是,编译器和 CPU 为了优化,可能会该改变这两个操作的执行顺序 (因为它们之间互不依赖),先对37号位置赋值,再对42号位置赋值。而执行到一半的时候,Worker 线程可能就会来读取数据,导致打印出` 123456 ` 和` 191 ` 。
1095
+ 上面代码中,主线程的原始顺序是先对42号位置赋值,再对37号位置赋值。但是,编译器和 CPU 为了优化,可能会改变这两个操作的执行顺序 (因为它们之间互不依赖),先对37号位置赋值,再对42号位置赋值。而执行到一半的时候,Worker 线程可能就会来读取数据,导致打印出` 123456 ` 和` 191 ` 。
1096
1096
1097
1097
下面是另一个例子。
1098
1098
@@ -1112,7 +1112,7 @@ Atomics.add(ia, 112, 1); // 正确
1112
1112
1113
1113
上面代码中,Worker 线程直接改写共享内存` ia[112]++ ` 是不正确的。因为这行语句会被编译成多条机器指令,这些指令之间无法保证不会插入其他进程的指令。请设想如果两个线程同时` ia[112]++ ` ,很可能它们得到的结果都是不正确的。
1114
1114
1115
- ` Atomics ` 对象就是为了解决这个问题而提出,它可以保证一个操作所对应的多条机器指令,一定是作为一个整体运行的,中间不会被打断。也就是说,它所涉及的操作都可以看作是原子性的单操作,这可以避免线程竞争() ,提高多线程共享内存时的操作安全。所以,` ia[112]++ ` 要改写成` Atomics.add(ia, 112, 1) ` 。
1115
+ ` Atomics ` 对象就是为了解决这个问题而提出,它可以保证一个操作所对应的多条机器指令,一定是作为一个整体运行的,中间不会被打断。也就是说,它所涉及的操作都可以看作是原子性的单操作,这可以避免线程竞争,提高多线程共享内存时的操作安全。所以,` ia[112]++ ` 要改写成` Atomics.add(ia, 112, 1) ` 。
1116
1116
1117
1117
` Atomics ` 对象提供多种方法。
1118
1118
0 commit comments