Javascript 把一个大斑点复制给一个工人是否很昂贵?
使用Fetch API,我能够对大量二进制数据(比如超过500 MB)发出网络请求,然后将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堆中,而是
响应
转换为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进行后期消息传递一点也不贵
水滴的形状是
它们的序列化步骤(给定值并序列化)为:
这个问题真的很有趣,但是取而代之的是从工作者那里获取文件有限制吗?@AntoineRaoulIscaros是的,对于这个特殊的情况,我需要首先从主线程获取。我明白了!我认为关于1。尽管请求Blob是一个额外的步骤,但正如浏览器上所述(至少是Chrome),它可以决定如何更好地存储数据,从而卸载页面堆。关于2。使用Blob的一个优点是执行Emscripten的WORKERFS正在执行的操作,逐块读取Blob。它速度较慢,但似乎内存效率更高。我不认为将Blob的数据和其中的一块作为ArrayBuffer比始终使用数据的单个副本在内存方面更好。我也不指望这篇论文能让一个浏览器实现优化。它看起来相当古老(例如,它似乎没有将ReadableStreams考虑在内),而且我很确定从那时起事情已经发生了变化。我仍然建议尽量保持原始状态,并转移所需的唯一ArrayBuffer。