作者:Lin Clark
译者:Cody Chan
原帖链接:A cartoon intro to ArrayBuffers and SharedArrayBuffers

这是图解 SharedArrayBuffers 系列的第二篇:

  1. 内存管理碰撞课程

  2. 图解 ArrayBuffers 和 SharedArrayBuffers

  3. 用 Atomics 避免 SharedArrayBuffers 竞争条件

上一篇文章中,我解释了 JavaScript 这类自动管理内存的语言是如何处理内存的,同样也解释了类似 C 语言这种手动管理内存的语言

为什么这对于我们讨论的 ArrayBuffers 和 SharedArrayBuffers 如此重要?

因为即使你使用的是 JavaScript 这种自动管理内存的语言,ArrayBuffers 也提供了一种手动处理数据的途径

为什么你会有这样的需求呢?

正如上篇文章所说,这里有个权衡,自动管理内存对开发者是友好的,但是这会增加机器负担,甚至会有性能问题

例如,JS 里创建一个变量,引擎会去猜测变量的类型以及内存里如何表示。因为有了类型猜测,JS 引擎通常会比真实需要预留更多的空间。根据变量不同,内存分配可能会是真实需求的 2-8 倍,这导致了内存浪费

而且,某些创建和使用 JS 对象的场景会让垃圾回收变得很困难。如果你是手动维护的内存,可以根据实际使用需求来决定分配和释放内存的策略

很多时候,这不是什么大不了的事。大多数场景并不会对性能要求那么苛刻,反而更多地担心管理内存的麻烦。而且一般情况下,手动管理内存可能更慢

但是对于底层需要极致优化的场景,ArrayBuffers 和 SharedArrayBuffers 为你提供了可能

ArrayBuffer 是如何工作的

ArrayBuffer 跟其它 JavaScript 数组差不多,但是不是所有 JavaScript 类型都可以放进去,比如对象、字符串。你唯一可以放进去的只有字节(可以用数字表示)

需要澄清的一点是,你事实上不是直接把这个字节到 ArrayBuffer 里就行了,ArrayBuffer 并不知道字节有多长,该用多少位去存

ArrayBuffer 仅仅是一个个 0/1 组成的串,它不知道第一个元素和第二个元素的分割点

为了提供必要的上下文信息,把 ArrayBuffer 分块,我们需要把它包裹到视图里,这些数据的视图可以通过带类型的数组添加,已经支持很多种类型的数组了

例如,你可以用一个 Int8 类型的数组把 0/1 串分割成 8 位一组的序列

或者你可以用一个无符的 Int16 类型数组,把它分割成 16 位一组的序列,可以把它当作无符整型处理

甚至你可以在同一个基础 buffer 上同时处理多种视图,不同视图在相同操作下会返回不同的结果

例如,如果我们从某个 ArrayBuffer 的 Int8 视图得到第 0 和第 1 个元素的值,在 Uint16 视图下,第 0 个元素与其有相同二进制位值,但是得到的值也会不一样

这种方式下,ArrayBuffer 几乎是扮演原始内存角色了,它模拟内存的各种跟 C 语言里类似的操作

你可能纳闷了,为什么不让开发者直接操纵内存而是采用这个抽象层。因为直接操作内存会有安全风险,这个以后的文章会讲

什么是 SharedArrayBuffer

为了说明白 SharedArrayBuffers,我需要稍微解释下并行运行代码和 JavaScript 的关系

为了更快运行代码或者更更快响应用户事件,你可能会让代码并行运行,为了做到这点,你需要分割工作

一个典型的应用中,所有的工作都由一个单独的主线程处理,这点我之前提到过……这个主线程就像一个全栈工程师,掌管着 JavaScript、DOM 和 视图

任何能够从主线程负载减少工作的方法都对代码运行效率有帮助,某些情况下,ArrayBuffers 可以减少大量应该由主线程做的工作

但是也有些时候减少主线程负载是远远不够的,有时你需要增援,你需要分割你的任务

大多数语言里,这种分割工作的方法可以使用多线程实现,这就像很多人同时在一个项目里工作。如果你可以完美地把任务分割为多个独立的部分,你可以分给不同的线程,然后,这些线程就同时各种独立执行这些任务

在 JavaScript 里,你可以借助 web worker 做这种事,这些 web workers 跟其它语言的线程还是有些区别的,默认它们不能共享内存

这意味着如果你想分配你的任务给别的线程,你需要完整把任务复制过去,这可以通过 postMessage 实现

postMessage 把你传给它的任何对象都序列化,发送到其它 web worker,然后那边接收后反序列化并放进内存

这个过程是非常慢的

某些类型数据(如 ArrayBuffers)你可以通过移动内存的方式实现,这意味着把某个特定区域的内存移过去后其它 web worker 就可以直接访问了

但是,之前的 web worker 就无法访问了

对于某些场景这是实用的,但是也有很多场景对性能要求高,你只能使用共享的内存

而这就是 SharedArrayBuffers 为你提供的

有了 SharedArrayBuffer 后,多个 web worker 就可以同时读写同一块内存了

你再也不需要 postMessage 伴有时延的通信了,多个 web worker 对数据访问都没有时延了

当然,这种同时访问也有风险,会产生竞争条件

这个下一篇文章会细说

SharedArrayBuffers 支持情况

所有主流浏览器都将会支持 SharedArrayBuffers

Safari 10.1 已经支持了,Firefox 和 Chrome 也会很快支持并发布,Edge 会在他们秋季 Windows 更新的时候发布

即使所有主流浏览器都支持了,我们也不希望开发者直接使用它们,事实上,我们是反对的。你应该只使用更高级的封装好的抽象层接口

我们期盼的是 JavaScript 库开发者可以提供更简单安全的方法来使用 SharedArrayBuffers

而且,一旦 SharedArrayBuffers 内置到平台中,WebAssembly 可以通过它实现多线程,到那时候你就可以使用类似 Rust 的多线程语言轻松玩转多线程了

下一篇文章我们会介绍一个为避免竞争条件的库提供基础操作的工具(Atomics

------------------------------------------------------------------------------------------

本文转载自:

https://segmentfault.com/a/1190000009878632

「译」图解 ArrayBuffers 和 SharedArrayBuffers的更多相关文章

  1. 「译」JUnit 5 系列:条件测试

    原文地址:http://blog.codefx.org/libraries/junit-5-conditions/ 原文日期:08, May, 2016 译文首发:Linesh 的博客:「译」JUni ...

  2. 「译」JUnit 5 系列:扩展模型(Extension Model)

    原文地址:http://blog.codefx.org/design/architecture/junit-5-extension-model/ 原文日期:11, Apr, 2016 译文首发:Lin ...

  3. 「译」JavaScript 的怪癖 1:隐式类型转换

    原文:JavaScript quirk 1: implicit conversion of values 译文:「译」JavaScript 的怪癖 1:隐式类型转换 译者:justjavac 零:提要 ...

  4. jvm系列(十):如何优化Java GC「译」

    本文由CrowHawk翻译,是Java GC调优的经典佳作. 本文翻译自Sangmin Lee发表在Cubrid上的"Become a Java GC Expert"系列文章的第三 ...

  5. jvm系列(七):如何优化Java GC「译」

    本文由CrowHawk翻译,地址:如何优化Java GC「译」,是Java GC调优的经典佳作. Sangmin Lee发表在Cubrid上的”Become a Java GC Expert”系列文章 ...

  6. iOS 9,为前端世界都带来了些什么?「译」 - 高棋的博客

    2015 年 9 月,Apple 重磅发布了全新的 iPhone 6s/6s Plus.iPad Pro 与全新的操作系统 watchOS 2 与 tvOS 9(是的,这货居然是第 9 版),加上已经 ...

  7. 「译」forEach循环中你不知道的3件事

    前言 本文925字,阅读大约需要7分钟. 总括: forEach循环中你不知道的3件事. 原文地址:3 things you didn't know about the forEach loop in ...

  8. 「译」JUnit 5 系列:环境搭建

    原文地址:http://blog.codefx.org/libraries/junit-5-setup/ 原文日期:15, Feb, 2016 译文首发:Linesh 的博客:环境搭建 我的 Gith ...

  9. 「译」JUnit 5 系列:架构体系

    原文地址:http://blog.codefx.org/design/architecture/junit-5-architecture/ 原文日期:29, Mar, 2016 译文首发:Linesh ...

随机推荐

  1. vue.js之组件篇

    Vue.js 组件 模块化:是从代码逻辑的角度进行划分的: 组件化:是从UI界面的角度进行划分的. 组件(Component)是 Vue.js 最强大的功能之一,组件可以扩展 HTML 元素,封装可重 ...

  2. Ajax常见面试题

    1,什么是ajax? 为什么要使用ajax? 1.ajax是"asynchornous javascript and xml "的缩写,指一种创建交互式网页应用的网页开发技术. 2 ...

  3. python的学习笔记01_3 基本运算符 流程控制if while 字符串常用办法

    基本运算符 运算符 计算机可以进行的运算有很多种,可不只加减乘除这么简单,运算按种类可分为算数运算.比较运算.逻辑运算.赋值运算.成员运算.身份运算.位运算,今天我们暂只学习算数运算.比较运算.逻辑运 ...

  4. Git - git tag - 查看当前分支 tag 版本&说明

    索引: 目录索引 参看代码 GitHub: git.txt 一.示例: git tag -l -n 二.说明: 1."tag" 部分 tag 代表的是标签动作,可以带参数 ,也可以 ...

  5. iBatis第三章:iBatis的基本用法

    iBatis 在DAO层的用法很基础,和一般 JDBC 用法没太多的不同之处,主要是实现数据的持久化.它的优势是用法比较灵活,可以根据业务需要,写出适应需要的sql,其使用简单,只要会使用sql,就能 ...

  6. FPGA设计千兆以太网MAC(3)——数据缓存及位宽转换模块设计与验证

    本文设计思想采用明德扬至简设计法.上一篇博文中定制了自定义MAC IP的结构,在用户侧需要位宽转换及数据缓存.本文以TX方向为例,设计并验证发送缓存模块.这里定义该模块可缓存4个最大长度数据包,用户根 ...

  7. 在Windows 10 x64 编译ReactOS-0.4.5源码并在VMare中运行

    1.首先下载ReactOS源码(版本是0.4.5,最新版本0.4.9暂没有编译),然后下载RosBe(版本是2.1.6) 2.将下载好的ReactOS源码包放到指定磁盘的文件夹中,目录路径为英文(重要 ...

  8. PLSQL Developer图形化界面新建用户并授权并导入脚本

    最近用了PLSQL Developer第三方的软件.记录一下实现新建用户并授权并导入脚本的功能. 第一步.切换sys用户(如果此处方法已经掌握,直接切换sys即可,就不用看这一步了) 首先检查当前登录 ...

  9. Loj #3096. 「SNOI2019」数论

    Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...

  10. EntityFramework Core 2.1重新梳理系列属性映射(一)

    前言 满血复活啦,大概有三个月的时间没更新博客了,关于EF Core最新进展这三个月也没怎么去看,不知现阶段有何变化没,本文将以EF Core 2.1稳定版本作为重新梳理系列,希望对看本文的你有所帮助 ...