更新
Chrome、Edge 和 Firefox 的现代版本现在支持 SharedArrayBuffers(尽管在撰写本文时还没有 safari see SharedArrayBuffers on MDN),因此这将是另一种快速传输数据的可能性,与一组不同的权衡相比到可转让的 (you can see MDN for all the trade offs and requirements of SharedArrayBuffers)。
更新:
According to Mozilla SharedArrayBuffer 已在所有主流浏览器中禁用,因此以下 EDIT 中描述的选项不再适用。
请注意,SharedArrayBuffer 在所有主要版本中都默认禁用
2018 年 1 月 5 日浏览器响应 Spectre。
编辑: 现在有另一个选项,它正在发送一个 sharedArray 缓冲区。这是共享内存和原子下的 ES2017 的一部分,现在在 FireFox 54 Nightly 中得到支持。如果您想了解它,可以查看here。我可能会写一些东西并将其添加到我的答案中。我也会尝试添加到性能基准中。
回答原问题:
我正在研究网络工作者,我正在将大量数据传递给
网络工作者,这需要很多时间。我想知道效率
发送数据的方式。
@MichaelDibbets answer 的替代方案是将对象的副本发送给 webworker,使用的是零拷贝的transferrable object。
这表明您打算让您的数据可传输,但我猜它没有成功。因此,我将解释一些数据对于您和未来的读者可转移意味着什么。
“通过引用”传输对象(尽管这不是它的完美术语,正如在下一个引用中解释的那样)不仅仅适用于任何 JavaScript 对象。它必须是可传输的数据类型。
[With Web Workers] 大多数浏览器都实现了结构化克隆
算法,它允许您将更复杂的类型传入/传出
Worker,例如 File、Blob、ArrayBuffer 和 JSON 对象。然而,
当使用 postMessage() 传递这些类型的数据时,仍然有一个副本
制作。因此,如果您要传递一个 50MB 的大文件(例如),
在工作人员之间获取该文件有明显的开销
和主线程。
结构化克隆很棒,但一个副本可能需要数百个
毫秒。为了对抗性能命中,您可以使用 Transferable
对象。
使用 Transferable Objects,数据从一个上下文传输到
其他。它是零拷贝,极大地提高了
向 Worker 发送数据。如果你是
来自 C/C++ 世界。但是,与传递引用不同,“版本”
一旦转移到调用上下文中就不再可用
新的语境。例如,当从
你的主应用程序到 Worker,原来的 ArrayBuffer 被清除并且没有
可用时间更长。它的内容(从字面上看是安静的)转移到
工作人员上下文。
- Eric Bidelman Google 开发人员,来源:html5rocks
唯一的问题是目前只有two things that are transferrable。 ArrayBuffer 和 MessagePort。 (Canvas Proxies 希望稍后发布)。 ArrayBuffers 不能直接通过其 API 进行操作,应用于创建 typed array object 或 DataView 以提供对缓冲区的特定视图并能够对其进行读取和写入。
来自 html5rocks 链接
要使用可转移对象,请使用稍微不同的签名
postMessage():
worker.postMessage(arrayBuffer, [arrayBuffer]);
window.postMessage(arrayBuffer, targetOrigin, [arrayBuffer]);
工人案例,第一个参数是数据,第二个是
应转移的物品清单。第一个论点不
顺便说一句,必须是一个 ArrayBuffer 。例如,它可以是 JSON
对象:
worker.postMessage({data: int8View, moreData: anotherBuffer}, [int8View.buffer, anotherBuffer]);
所以根据你的
var worker = new Worker('js2.js');
worker.postMessage(buffer, [ buffer]);
worker.postMessage(obj, [obj.mat2]);
应该以极快的速度执行,并且应该以零拷贝方式传输。唯一的问题是您的buffer 或obj.mat2 不是ArrayBuffer 或可转让。您可能会将 ArrayBuffers 与 typed array 的视图混淆,而不是您应该使用它的缓冲区。
所以如果你有这个 ArrayBuffer 并且它是 Int32 表示。 (虽然变量的标题是视图,但它不是 DataView,但 DataView 确实有一个属性缓冲区,就像类型化数组一样。此外,在编写此内容时,MDN 使用名称“view”作为调用类型化数组构造函数的结果所以我认为这是定义它的好方法。)
var buffer = new ArrayBuffer(90000000);
var view = new Int32Array(buffer);
for(var c=0;c<view.length;c++) {
view[c]=42;
}
这是你应该不做的(发送视图)
worker.postMessage(view);
这是你应该做的(发送 ArrayBuffer)
worker.postMessage(buffer, [buffer]);
这些是运行this test on plnkr后的结果。
Average for sending views is 144.12690000608563
Average for sending ArrayBuffers is 0.3522000042721629
编辑:正如@Bergi 在the comments 中所述,如果您有视图,则根本不需要缓冲区变量,因为您可以像这样发送view.buffer
worker.postMessage(view.buffer, [view.buffer]);
作为对未来读者的附注,只是发送一个 ArrayBuffer 而没有最后一个参数指定 ArrayBuffer 是什么,你不会发送 ArrayBuffer 可转移
换句话说,在发送可转让物品时,您需要这样:
worker.postMessage(buffer, [buffer]);
不是这个:
worker.postMessage(buffer);
编辑:最后一点,因为您正在发送缓冲区,请不要忘记在 webworker 收到缓冲区后将其转回视图。一旦它是一个视图,您就可以再次对其进行操作(读取和写入)。
为了赏金:
我也对 firefox/chrome 的官方尺寸限制感兴趣(不是
只有时间限制)。但是回答原始问题有资格
赏金 (;
至于网络浏览器限制发送一定大小的东西,我不完全确定,但从 Eric Bidelman 的 html5rocks 条目中谈到工人时,他确实提出了一个 50 mb 的文件,该文件在不使用可传输设备的情况下被传输数据类型在数百毫秒内,如我的测试所示,使用可转移数据类型只需大约一毫秒。哪一个 50 mb 真的很大。
纯粹是我个人的观点,但我认为除了数据类型本身的限制之外,对于可传输或不可传输数据类型发送的文件大小没有限制。当然,您最担心的可能是浏览器停止长时间运行的脚本,如果它必须复制整个内容并且不是零复制和可转移的。
希望这篇文章有所帮助。老实说,在此之前我对可转移对象一无所知,但通过一些测试和 Eric Bidelman 的博文了解它们很有趣。