我一直在优化一些长期运行的JAvaScript,并尝试实现WebWorkers。
我有一组要计算的独立任务。在我的初始测试中,有80个任务,并且在主线程中以250ms完成。我以为我可以将任务分配给某些Web worker ,并将时间缩短到50毫秒左右。
我的数据是嵌套多个类型数组的几何数据结构。我有将所有数据提取到JSON + ArrayBuffer对象数组的方法,因此我可以将传输的数据传递给WebWorker,而无需复制大数组。
这是我的WebWorker脚本。
importScripts('../lib/MyLib.js');
let timeComputing = 0;
this.onmessage = function(e) {
switch (e.data.msg) {
case 'compute':
let mesh = ... unpack data;
let start = performance.now();
mesh.doexpensiveCompute();
timeComputing += performance.now() - start;
... send data back to the main thread.
break;
case 'logTime':
console.log("timeComputing:" + timeComputing);
}
}
当工作人员记录正在使用的时间时,通常每个工作人员大约130毫秒,这意味着总时间实际上接近500毫秒。主线程在250毫秒内完成所有工作,因此使用WebWorkers的速度要慢100%。由于某种原因,在WebWorker中运行的完全相同的代码要比在主线程上运行的速度慢得多。
我很快就会遇到的一些工作负载可能包含数百个任务,因此我希望WebWorkers可以使我的页面保持响应状态。 (目前,在高负载情况下根本不存在)。
关于我为什么看到如此糟糕的结果,有人会提出任何建议吗?注意:我在这里消除了数据传输(我认为这是最小的)和线程启动的开销。我纯粹是在测量 worker 的计算时间,这很可怜...有没有人有在Webworker中运行繁重的计算任务的经验?
一种想法是,我的工作脚本也加载了我的主机脚本。 (示例代码中的MyLib.js),这是一个Webpacked脚本,并且很大。我使用它是为了希望浏览器缓存将意味着它不需要再次请求。也许相反,我应该只为Webworker上下文生成引擎的最低版本。
谢谢你的提示...
最佳答案
我现在调试了我的 worker 。
importScripts('../lib/MyLib.js');
最初,我以为在工作线程中重用我的主库js文件将使浏览器能够使用lib的缓存版本。 IE。浏览器将不需要HTTP请求文件或对其进行编译,因为它已经在内存中了。事实证明这是错误的,浏览器需要重新请求文件并重新编译它。
因为我的脚本很大,所以重新编译成为了很大的开销,因为它似乎还需要为每个线程重新编译。通过测量每个任务的往返时间,同时在 worker 中执行零工作,我得出了这个结论。每个线程的往返时间开始很长(300毫秒),经过几次迭代后迅速降至
现在,我使用一个内联的Web工作程序来避免额外的请求,并保持我的库处于封装状态,如下所述:http://www.html5rocks.com/en/tutorials/workers/basics/#toc-inlineworkers
并且还为工作人员使用了缩减的脚本。
我现在表现出色。 250毫秒约为50毫秒。第一次往返很慢,但还算不错,并且内联Web worker使其快得多。