1
0
mirror of https://github.com/ruanyf/es6tutorial.git synced 2025-05-24 18:32:22 +00:00

docs(ArrayBuffer): edit ArrayBuffer

This commit is contained in:
ruanyf 2017-08-01 07:02:24 +08:00
parent c850187bd7
commit 11f7f679c7

View File

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