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
答案 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工作者转移。这就像通过引用传递没有复制的地方。它与正常的引用传递之间的区别在于传输数据的一方无法再访问它。