web worker和主线程的数据交换效率初探
概述
web worker是浏览器的多线程机制,多用于处理不涉及DOM操作的密集计算任务,例如算法计算,数据请求处理等,我正在开发的开源地图引擎 maptalks.js 中对地图数据的处理就很适合放到web worker中(突兀的硬广 ^_^)。
web worker最大的优点是形式简单:
- worker的运行上下文(context)与主线程独立,无法互相调用,避免了多线程编程中的线程锁等复杂机制
- worker只能通过postMessage和onmessage与主线程交换数据
所以,worker程序的性能很大程度上取决于与主线程之间数据交换效率。
- 默认情况下,postMessage中数据是采用结构化克隆(structrured clone)算法来实现跨进程传送的。
- 引进Web Worker接口时,浏览器同时引进了Transferable和ArrayBuffer这一对好基友,当传送的数据为Transferable时,浏览器能通过只传送数据引用(指针),而不是结构化克隆(structrured clone)来极大的提高数据传送效率,具体可以参考google的Transferable Objects: Lightning Fast!(需翻墙)。
问题
当传送数据结构不复杂时(类型化数组,字符串等),我们有两种可选的数据传送方式:
- 直接用postMessage({ data })传送,让浏览器用structured clone算法拷贝数据到主线程
- 参考谷歌文章,将数据先转化为ArrayBuffer(Transferable),然后直接传引用给主线程,无需structured clone
如果数据本身已经是类型化数组,毫无疑问方式二更好。
但如果有很多简单数据(类型化数组或字符串),将这些数据转化为ArrayBuffer后采用Transferable传送,相比浏览器的structured clone,哪个效率更高?
测试
为此,我写了一个jsperf测试程序。
测试数据为100K字节的整数数组和200K字节的字符串数组,创建以下四个测试用例:
- 封装成对象,直接传送数据 (structured clone传送)
- 拷贝为新的数组后,封装成对象传送 (structured clone传送)
- 将数组转化为ArrayBuffer,转化方式用传统的遍历循环数据 (Transferable传送)
- 将数组转化为ArrayBuffer,转化方式用TypedArray.prototype.set批量转化 (Transferable传送)
测试结果取决于浏览器:
- 在chrome 64和firefox 58下, 都是方式4最快,但chrome上方式3最慢
- firefox下方式1,2最慢,与3,4差距很大
- 在ie 11下,1最快,3最慢,但4与1的差距并不大
结论
- 综合来看,数据结构简单时,转化成ArrayBuffer,用Transferable方式传送性能更好
- ArrayBuffer的转化方式很重要,用Array.prototype.set,而不是循环遍历
- 除了100K + 200K,也测试了其他数据,结论仍然成立
最后附上我本机的测试结果:
Chrome 64:
Firefox 58:
IE11:
相关推荐
zhoujiyu 2020-06-28
瓜牛呱呱 2020-11-12
starinshy 2020-11-10
farewellpoem 2020-11-09
Charlesbases 2020-10-23
arctan0 2020-10-14
hackerlpy 2020-09-25
温攀峰 2020-09-16
天空一样的蔚蓝 2020-09-04
ericxieforever 2020-09-03
cyhgogogo 2020-08-18
大唐帝国前营 2020-08-18
yuanlu 2020-08-17
deepSTEM 2020-08-16
chunjiekid 2020-08-16
lhtzbj 2020-08-13
shonmark 2020-08-03
cuiweisaidelike 2020-08-02
comeonxueRong 2020-08-02