为什么javascript中的传输缓冲区是绝对的?

时间:2016-07-03 11:53:00

标签: javascript web-worker

Javascript允许将缓冲区从源线程转移到Worker线程。否则,复制ArrayBuffer,然后传递给worker。传送的缓冲区在源线程[1]中不可访问(“neutered”):

// create data that can be transfered
var arr = new Uint8Array(5);

// outputs: 5
console.log(arr.buffer.byteLength);

var worker = new Worker("some_worker.js");

// transfer the buffer
worker.postMessage({arr: arr}, [arr.buff]);

// the buffer vanishes. is "Neutered"
// outputs: 0
console.log(arr.buffer.byteLength);

我了解机制是如何运作的。然而,我很好奇它为何被引入。为什么工作线程之间不共享数据,就像在传统的线程模型中一样,它允许多个线程访问相同的线程 记忆区?

同一问题的其他措辞澄清:

为什么缓冲区在转移时会被绝育? /这种机制背后的原因是什么? /为什么介绍它?为什么不能在Workers之间共享内存区域?

我正在寻找可信和/或官方消息来源的答案。

[1] https://developer.mozilla.org/en/docs/Web/API/Worker/postMessage

7 个答案:

答案 0 :(得分:15)

Web Workers中引入了可转移对象,以提高性能与复制对象(特别是当我们谈论大尺寸对象时)。它可以与通用编程语言(例如C / C ++)中的pass-by-value和pass-by-reference之间的比较并行化。

可能添加了可转换对象不能在源工作线程中使用的进一步限制,因此可以保证两个不同线程之间不存在竞争条件(为了方便开发人员的工作)不必关心那个)。此外,还需要在Javascript中实现更多的并发原语(例如互斥体等)。从本质上讲,使用" transfer"意味着你只是打算将数据传输到另一个线程,而不是同时从2个线程使用它们,所以我们可以说实现是有意义的。

通常,Web Workers不是设计为共享内存模型,而是设计为消息交换模型。

有关性能差异的进一步阅读,请检查this。您还可以查看this,其中讨论了WebKit中Web Workers未采用共享内存模型的原因。

答案 1 :(得分:7)

这是一个非常基本的多线程问题。如果可以在主线程和工作线程中访问阵列,则必须实现互斥锁,以便在访问缓冲区时不会出现竞争条件。另外,我认为当你想要性能时通常使用数组缓冲区,但是从该缓冲区读取/写入数据的锁定会使工作者变慢。

我想这是资源被移动的原因之一"而不是分享。

TL; DR :多线程

答案 2 :(得分:3)

原因是表现。未复制发送的数据,ArrayBuffer的所有权将传输到接收方。

对于共享内存,您应该使用SharedArrayBuffer

答案 3 :(得分:3)

根据WHATWG ML,选择是thread safe,因为

  

您无法在员工之间共享数据。 JS执行的多个线程之间没有(也没有)任何共享状态。

source

另外,

  

我们想要   使源ArrayBuffer和任何ArrayBufferViews的长度为零   将它们发布给工作者或返回主线程。通过   你可以避免来回ping相同的ArrayBuffer   每次迭代都会分配新的后备存储。

source

不幸的是,我没有找到关于规范的讨论,the page应该托管的地方给出404,我会尝试在其他地方找到副本

答案 4 :(得分:1)

要明确传输适用于专用和共享工作者,因为它们都使用MessagePorts

  

[1]专职工作人员在幕后使用MessagePort对象。

     

[2]使用显式MessagePort对象与共享工作人员进行通信

指定postMessage根据来电者的选择进行转移或克隆

  

[3] port.postMessage(message [,transfer])   通过频道发布消息。 传输中列出的对象,而不仅仅是克隆,这意味着它们在发送方不再可用。

然而,这仅表明海报是否保留副本,通常基于效率,而不是共享任何内存。

说到" 记忆"明确规定,无论工人类型如何或者数据被转移或克隆,都不得共享

  

[4]当用户代理要为具有URL网址的脚本,环境设置对象设置对象和URL引用来运行工作程序时,必须运行以下步骤:< / p>      

创建一个单独的并行执行环境(即单独的线程或进程或等效构造),并在该上下文中运行其余步骤。

现在问题是:为什么?为什么必须用户代理为任何和所有类型的工作者创建并行执行环境?

安全?号码效率? (因为什么时候js有效?),都没有。

原因是能够遵守或者更加尊重整个规范。如果您按照link [4]至少注意到:

  

当用户代理要终止工作时,它必须与工作人员的主循环并行运行以下步骤(&#34;运行工人&#34;上面定义的处理模型):

     

1)将worker的WorkerGlobalScope对象的关闭标志设置为true。

     

2)如果在WorkerGlobalScope对象的事件循环任务队列中排队了任何任务,则丢弃它们而不处理它们。

     

3)中止当前在工作人员中运行的脚本。

     

4)如果worker的WorkerGlobalScope对象实际上是DedicatedWorkerGlobalScope对象(即worker是一个专用worker),那么清空工作者隐式端口与之纠缠的端口的端口消息队列

这只是规范的一部分。

又是为什么?能够管理工作空间中发生的事件的总体情况。实施者必须与工人平行或完全疯了。 :)

答案 5 :(得分:0)

由于历史环境的影响,因为在工作人员被引入作为消息传递API [1]并且意图进行微小改变[2] [3]之后,可转换性被添加到规范中。

[1] https://bugzilla.mozilla.org/show_bug.cgi?id=720083(在Firefox中实施请求)

[2] https://mail.mozilla.org/pipermail/es-discuss/2014-May/037239.html

  

因为在HTML5中形式化了Transferable的概念   规范,有一个目标是尽可能做出最小的改变。   Transferable基本上是MessagePort的概括,即   以前唯一可以“转移”给Web工作者的类型。   绝育只是spec文本中的概念,而不是IDL中的概念。该   可转换的typedef没有任何相关的方法。唯一的办法   中性对象是将其传递给网络工作者。曾经有   请求提供“close()”方法并使Transferable成为a   新Closable接口的子接口。我们拒绝制作这些   因为它们基本上会引入手动内存而发生变化   管理到JavaScript。

[3] https://mail.mozilla.org/pipermail/es-discuss/2014-May/037227.html

  

首先,一些背景知识。设计类型数组时,它们是   使用Web IDL及其ECMAScript绑定指定。有尝试   在类型化数组的开发过程中,在某些类型上抛出异常   操作 - 比如超出范围的索引 - 但是这些操作一个接一个   发现与Web IDL或ECMAScript不兼容   像属性查找这样的语义。

答案 6 :(得分:0)

要在javascript中使用这些概念,您必须使用这些编码,

PostMesage(aMessage, transferList)

在transferList中,您必须指定包含在aMessage中的可转移对象:

var objData =
{
    str: "string",
    ab: new ArrayBuffer(100),
    i8: new Int8Array(200)
};
objWorker.postMessage(objData, [objData.ab, objData.i8.buffer]);

On other side:

self.onmessage = function(objEvent)
{
    var strText = objEvent.data.str;
    var objTypedArray = objEvent.data.ab;
    var objTypedArrayView = objEvent.data.i8;
}

要使用“可转移对象”,您实际上将对象的所有权转移到Web工作者或从Web工作者转移。这就像通过引用传递没有复制的地方。它与正常的引用传递之间的区别在于传输数据的一方无法再访问它。