在上一篇文章中,老司机带你了解了像 JavaScript 这样的语言是如何自动管理内存的。还解释了如何在 C 语言中手动管理内存。
我们为什么要在介绍 ArrayBuffers 和 SharedArrayBuffers 之前,先解释内存管理的知识呢?
这是因为,在 JavaScript 中,正是 ArrayBuffers 给你提供了手动管理内存的途径。
为什么要去手动管理内存呢?
正如我们在上一篇文章中谈到的关于自动内存管理的利弊:自动内存管理对开发人员来说比较友好。但它增加了一些额外的开销,在某些情况下,这些开销可能导致性能问题。
例如,当你在 JS 中创建变量时,引擎必须猜测它的数据类型,以及如何保存在内存中。因此,JS 引擎通常预留的空间比这个变量真正需要的空间大很多。根据变量的不同,内存分配可能会比实际需要的大2-8倍,这会导致大量的内存浪费。
此外, 某些创建和使用 JS 对象的模式会使收集垃圾变得更加困难。如果你手动管理内存的话, 可以根据实际使用需求来决定分配和释放内存的策略。
大多数时候, 这没什么大不了的。因为,大多数场景对性能要求并不苛刻,你无需手动管理内存。对于常见场景,手动内存管理甚至可能会更慢。
但是对于那些在底层需要极致优化的场景,ArrayBuffers 和 SharedArrayBuffers 就派上用场了。

那么 ArrayBuffer 怎么工作?

它基本上就像其它 JavaScript 数组一样。但是,ArrayBuffer 的元素必须是字节(可以用数字表示),对象或字符串这类的 JavaScript 类型的数据是不行的。
有一点我应该在这里明确指出,你并没有将这个字节直接添加到 ArrayBuffer 中。ArrayBuffer 本身并不知道字节应该有多大,也不知道不同的数字应该如何转换成字节。
ArrayBuffer 只是一串 0 和 1。它是不知道怎么拆分这个数组中各个元素的。
为了提供上下文信息,把 ArrayBuffer 拆分开,我们需要将它放在视图中。这些数据的视图可以添加类型化数组,并且有很多不同的类型数组可以使用。
例如,你可以使用 Int8 类型的数组,将 ArrayBuffer 分解为8位字节。
或者你可以用一个无符号的 Int16 类型数组,它可以将 ArrayBuffer 分解成16位不带符号整数。
同一 buffer 上可以有多个视图,不同的视图会为相同的操作提供不同的结果。
例如,我们从这个 ArrayBuffer 的 Int8 视图获取的元素,和从它的 Uint16 视图获取的元素就是不同的值,即使它们包含完全相同的 bits。
通过这种方式,ArrayBuffer 基本上就像原始内存,让你可以像使用 C 语言那样直接操作内存。
你可能会想知道为什么我们不让程序员直接访问内存,而是添加这一层抽象。这是因为直接访问内存将会打开一些安全漏洞。以后我会写一篇文章对此进行详细的解释。

那么 SharedArrayBuffer 是什么?

要解释 SharedArrayBuffers,我需要先解释一下并行运行代码和 JavaScript。
并行运行代码会使你的代码运行更快,也可以更快的响应用户的事件。要做到这一点,你需要先拆分工作。
在一个典型的应用中,所有工作全部单独由主线程来处理。主线程就像一个全栈开发者,它负责处理 JavaScript,Dom,和布局。
任何减少主线程工作负载的事对代码运行效率都是有帮助的。在某些情况下,ArrayBuffer 可以减少主线程的工作。
但有时仅仅减少主线程工作是不够的,你还需要一个增援来分担一部分工作。
大多数语言里,这种分割工作的方法可以使用多线程实现。这就像多人在一个项目上工作。如果有些任务是相互独立的且没有依赖,那么就可以把它们分配到不同线程上。然后,这些线程可以同时处理单独的任务。
在 JavaScript 中,可以通过 web worker 来实现这些,但跟其他语言中的线程处理方式有些不同。默认情况下,它们不共享内存。
这意味着,如果想处理一些其他线程上的数据,你不得不通过 postMessage 方法将数据完整的复制一份过来。
postMessage 会将你传进去的东西序列化,然后发送给另一个 web worker,那边会反序列化并放入内存中。
这是一个相当缓慢的过程。
对于某些数据,比如 ArrayBuffer,你还可以使用“转移内存”。这种方式会把指定区域的内存移动到另一个 web worker 那里。
但是之前的 web worker 将不再能访问这些被转移走的内存。
转移内存这种方式适用于某些场景,但是对于更多的高性能并行的场景,共享内存才是你真正想要的。
这就是 SharedArrayBuffers 能给你的。
有了 SharedArrayBuffers,多个 web workers,多个线程都可以在同一块内存上读写数据。
这意味着他们不会再有使用 postMessage 时的通讯开销和延迟。所有 web workers 都可以即时访问数据。
当然,多个线程同时访问内存是有风险的,这会引起条件竞争(race conditions)问题。
我会在下一篇中详细说明。
SharedArrayBuffers 的支持情况
SharedArrayBuffers 即将在所有主流浏览器中支持。
Safari 10.1 已经支持了,Firefox 和 Chrome 的版本 将在7月或8月发布。而 Edge 计划在秋季 Windows 的更新中得到支持。
即使所有主流浏览器都支持了,我们也不指望应用开发者们直接使用它们。事实上,我们也不推荐直接使用。你应该使用的是最顶部的抽象层。
我们希望 JavaScript 库的开发者们开发出更简单安全的使用 SharedArrayBuffers 的库。
此外,一旦 SharedArrayBuffers 内置到平台中,WebAssembly 可以利用它实现多线程。到那时,你就可以使用像 Rust 这种以处理并发性为目标的语言一样轻松的处理多线程。
下一章,我们将介绍那些库开发者们构建抽象同时又避免条件竞争(race conditions)所使用的工具 Atomics
 

看图学习 ArrayBuffers 和 SharedArrayBuffers的更多相关文章

  1. VS2017 community版使用码云(gitee)的一些过程,看图学习,傻瓜式教程

    首先你得有一个gitee账号,VS2017IDE开发工具 第一步,打开VS2017,点击菜单栏上->工具->扩展与更新,如图 然后点击 联机 然后输入 gitee 回车搜索 一定要选择我圈 ...

  2. (CV学习笔记)看图说话(Image Captioning)-1

    Background 分别使用CNN和LSTM对图像和文字进行处理: 将两个神经网络结合: 应用领域 图像搜索 安全 鉴黄 涉猎知识 数字图像处理 图像读取 图像缩放 图像数据纬度变换 自然语言处理 ...

  3. 学习笔记TF060:图像语音结合,看图说话

    斯坦福大学人工智能实验室李飞飞教授,实现人工智能3要素:语法(syntax).语义(semantics).推理(inference).语言.视觉.通过语法(语言语法解析.视觉三维结构解析)和语义(语言 ...

  4. 【转载】跟着9张思维导图学习JavaScript

    原文:跟着9张思维导图学习JavaScript 学习的道路就是要不断的总结归纳,好记性不如烂笔头,so,下面将 po 出我收集的 9 张 JavaScript相关的思维导图(非原创). 思维导图小ti ...

  5. Multimodal —— 看图说话(Image Caption)任务的论文笔记(一)评价指标和NIC模型

    看图说话(Image Caption)任务是结合CV和NLP两个领域的一种比较综合的任务,Image Caption模型的输入是一幅图像,输出是对该幅图像进行描述的一段文字.这项任务要求模型可以识别图 ...

  6. [看图说话]在VMware Workstation 9中安装Mac OS X 10.8 Mountain Lion

    本文环境: CPU:Intel Core i7 920: OS:Windows 7: 内存:8G: 玩Hackintosh各有各的理由,不管什么理由,利用虚拟机安装Mac OS X都是一个可行的办法. ...

  7. 跟着9张思维导图学习Javascript js 关键字和保留字 css3中的BFC,IFC,GFC和FFC

    跟着9张思维导图学习Javascript   学习的道路就是要不断的总结归纳,好记性不如烂笔头,so,下面将 po 出我收集的 9 张 javascript 相关的思维导图(非原创). 思维导图小ti ...

  8. 关于图计算&图学习的基础知识概览:前置知识点学习(Paddle Graph Learning (PGL))

    关于图计算&图学习的基础知识概览:前置知识点学习(Paddle Graph Learning (PGL)) 欢迎fork本项目原始链接:关于图计算&图学习的基础知识概览:前置知识点学习 ...

  9. 图学习【参考资料2】-知识补充与node2vec代码注解

    本项目参考: https://aistudio.baidu.com/aistudio/projectdetail/5012408?contributionType=1 *一.正题篇:DeepWalk. ...

随机推荐

  1. flask-migrate 处理sqlite数据库报错Constraint must have a name 的解决方案

    环境:flask+python+sqlite,我想给某个表里某个字段加unique属性 执行 python manage.py db migrate 没报错,执行 python manage.py d ...

  2. 谈谈 Qt4 中文乱码的解决

    本文只描述Qt4的解决方法,Qt5没有尝试过,不做讨论.网上关于这个话题一搜一大堆,基本无外乎字符集编码的理论,看不明白.直接上代码吧! #include "widget.h" # ...

  3. xshell乱码解决办法

    https://jingyan.baidu.com/article/7908e85c758a58af481ad2ae.html

  4. Android 用空格作为分割符切割字符串

    项目中有需要用到空格作为分割符切割字符串,进而转为List. String wordStore = edWord.getText().toString(); String[] word = wordS ...

  5. unity探索者之socket传输protobuf字节流(二)

    版权声明:本文为原创文章,转载请声明http://www.cnblogs.com/unityExplorer/p/6977935.html 上一篇主要说的是protobuf字节流的序列化和解析,将pr ...

  6. jqgrid 自定义文本框、选择框等查询

    要实现jqgrid的自定义查询可通过表格获取查询的条件,再给jqgrid表格发送postData参数. HTML: <table id="querytable" border ...

  7. Mybatis动态语句

    If元素If元素是简单的条件判断逻辑,满足制定条件时追加if元素的SQL,不满足条件时不追加,使用格式如下: <select ….> SQL语句1 <if test=“条件表达式”& ...

  8. express-session中的saveUninitialized和resave

    app.use(session({ name: config.session.name, secret: config.session.secret, resave: true, saveUninit ...

  9. JS - 对金额数字实现千分位格式化处理

    添加千分位处理: function fmoney(s, n) { n = n > 0 && n < = 20 ? n : 2; s = parseFloat((s + &q ...

  10. ReentrantLock可中断锁和synchronized区别

    ReentrantLock中的lockInterruptibly()方法使得线程可以在被阻塞时响应中断,比如一个线程t1通过lockInterruptibly()方法获取到一个可重入锁,并执行一个长时 ...