我一直在优化一些长期运行的JAvaScript,并尝试实现WebWorkers。

我有一组要计算的独立任务。在我的初始测试中,有80个任务,并且在主线程中以250ms完成。我以为我可以将任务分配给某些Web worker ,并将时间缩短到50毫秒左右。

我的数据是嵌套多个类型数组的几何数据结构。我有将所有数据提取到JSON + ArrayBuffer对象数组的方法,因此我可以将传输的数据传递给WebWorker,而无需复制大数组。

  • 我已经测试了数据传输,并确认它正在按预期工作。转移到WebWorker后,主线程中的“我的类型”数组为空。
  • 我(现在)启动了4位Web工作人员,因此,当需要完成工作时,工作人员应该准备好了。
  • 每个工作人员完成一项任务时,我将其留在队列中的下一个任务,直到队列为空。
  • 我跟踪网络 worker 的时间,以查看实际执行计算时使用了多少时间(例如,忽略数据传输开销)。
  • 我有一台8核笔记本电脑,每天运行多线程代码。

  • 这是我的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使其快得多。

    10-04 11:43