Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/472.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 把一个大斑点复制给一个工人是否很昂贵?_Javascript_Blob_Web Worker_Arraybuffer - Fatal编程技术网

Javascript 把一个大斑点复制给一个工人是否很昂贵?

Javascript 把一个大斑点复制给一个工人是否很昂贵?,javascript,blob,web-worker,arraybuffer,Javascript,Blob,Web Worker,Arraybuffer,使用Fetch API,我能够对大量二进制数据(比如超过500 MB)发出网络请求,然后将响应转换为Blob或ArrayBuffer 之后,我可以执行worker.postMessage并让标准结构化克隆算法将Blob复制到Web工作程序,或者将ArrayBuffer传输到工作程序上下文(使主线程不再有效) 首先,似乎更可取的做法是以ArrayBuffer的形式获取数据,因为Blob是不可传输的,因此需要进行复制。然而,blob是不可变的,因此,浏览器似乎不会将其存储在与页面关联的JS堆中,而是

使用Fetch API,我能够对大量二进制数据(比如超过500 MB)发出网络请求,然后将
响应
转换为
Blob
ArrayBuffer

之后,我可以执行
worker.postMessage
并让标准结构化克隆算法将
Blob
复制到Web工作程序,或者将
ArrayBuffer
传输到工作程序上下文(使主线程不再有效)

首先,似乎更可取的做法是以
ArrayBuffer
的形式获取数据,因为
Blob
是不可传输的,因此需要进行复制。然而,blob是不可变的,因此,浏览器似乎不会将其存储在与页面关联的JS堆中,而是存储在专用blob存储空间中,因此,最终复制到工作上下文的内容只是一个引用

我准备了一个演示来尝试这两种方法之间的区别:。我正在使用这两种方法获取656MB的二进制数据

我在本地测试中观察到的一个有趣的现象是,复制Blob比传输
ArrayBuffer
还要快:

Blob
从主线程到辅助线程的复制时间:1.828125毫秒

ArrayBuffer
从主线程到辅助线程的传输时间:3.393310546875毫秒

这是一个强有力的指标,表明处理斑点实际上相当便宜。由于它们是不可变的,浏览器似乎足够聪明,可以将它们作为引用,而不是将覆盖的二进制数据链接到这些引用

以下是我在作为
Blob
获取时拍摄的堆内存快照:

前两个快照是在使用
postMessage
将获取的
Blob
复制到工作上下文之后拍摄的。请注意,这两个堆都不包括656mbs

后两个快照是在我使用
FileReader
实际访问底层数据之后拍摄的,正如预期的那样,堆增长了很多

现在,这就是直接作为
ArrayBuffer
获取的情况:

这里,由于二进制数据只是通过工作线程传输的,因此主线程的堆很小,但工作线程堆包含656mbs的全部,甚至在读取此数据之前

现在,看看SO,我看到它提到了两种结构之间的许多潜在差异,但是我还没有找到一个很好的参考,关于执行上下文之间是否应该担心通过
Blob
进行复制,而不是
ArrayBuffer
的固有优势是它们是可转移的。然而,我的实验表明,复制
Blob
实际上可能更快,因此我认为更可取

这似乎取决于每个浏览器供应商如何存储和处理
Blob
s。我发现所有的
Blob
都从每个渲染器进程(即选项卡上的页面)传输到浏览器进程,这样Chrome甚至可以在需要时将
Blob
卸载到辅助内存


有人对这一切有更多的见解吗?如果我可以选择通过网络获取一些大型二进制数据并将其移动到Web工作者,我应该选择
Blob
还是
ArrayBuffer

不,对Blob进行后期消息传递一点也不贵

水滴的形状是

它们的序列化步骤(给定值并序列化)为:

  • 将序列化的。[[SnapshotState]]设置为值的快照状态

  • 将序列化的。[[ByteSequence]]设置为值的基础字节序列

  • 给定序列化和值,其反序列化步骤为:

  • 将值的快照状态设置为序列化。[[SnapshotState]]

  • 将值的基础字节序列设置为序列化。[[ByteSequence]]

  • 换句话说,不复制任何内容,快照状态和字节序列都是通过引用传递的(即使包装JS对象不是)

    但是,关于您的整个项目,我不建议在这里使用BLOB,原因有二:

  • fetch算法首先在内部作为ArrayBuffer进行获取。请求一个Blob会增加一个额外的步骤(这会消耗内存)
  • 您可能需要从Worker读取该Blob,并添加另一个步骤(这也将消耗内存,因为在这里数据实际上会被复制)

  • 这个问题真的很有趣,但是取而代之的是从工作者那里获取文件有限制吗?@AntoineRaoulIscaros是的,对于这个特殊的情况,我需要首先从主线程获取。我明白了!我认为关于1。尽管请求Blob是一个额外的步骤,但正如浏览器上所述(至少是Chrome),它可以决定如何更好地存储数据,从而卸载页面堆。关于2。使用Blob的一个优点是执行Emscripten的WORKERFS正在执行的操作,逐块读取Blob。它速度较慢,但似乎内存效率更高。我不认为将Blob的数据和其中的一块作为ArrayBuffer比始终使用数据的单个副本在内存方面更好。我也不指望这篇论文能让一个浏览器实现优化。它看起来相当古老(例如,它似乎没有将ReadableStreams考虑在内),而且我很确定从那时起事情已经发生了变化。我仍然建议尽量保持原始状态,并转移所需的唯一ArrayBuffer。