WebWorkers执行似乎比主线程慢得多 [英] WebWorkers execution appears to be much slower than the main thread

查看:106
本文介绍了WebWorkers执行似乎比主线程慢得多的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have been working on optimizing some long running JAvaScript, and tried implementing WebWorkers.

我有一系列要计算的独立任务。在我的初始测试中有80个任务,并且在主线程上完成250ms。我认为我可以将任务分配给一些网络工作者,并将时间缩短到50毫秒。

I have a collection of independent tasks to compute. In my initial test there are 80 tasks, and on the main thread the complete in 250ms. I thought that I could distribute the tasks across some web workers and get the time down to maybe 50ms.

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

My data is geometry data structures that nest multiple typed arrays. I have methods that extract all the data to JSON + an array of ArrayBuffer objects, and so I can pass the data as transfered to the WebWorker without duplicating the big arrays.


  • 我测试了数据传输,并确认它正在按预期工作。传输到WebWorker后,我的Typed数组在主线程中为空。

  • 我预先启动(现在)4名网络工作人员,这样当需要完成工作时,工作人员应该做好准备。

  • 当每个工作人员完成一项任务时,我会在队列中为其提供下一个任务,直到队列为空。

  • 我在网络工作者中跟踪时间,看看在实际计算中使用了多少(例如忽略数据传输开销)。

  • 我有一台8核笔记本电脑,每天运行多线程代码。

  • I have tested the data transfer, and confirmed that it is working as expected. My Typed arrays are empty in the main thread after transferring to the WebWorker.
  • I launch (for now) 4 web workers up front, so that when the work is needed to be done, the workers should be ready.
  • As each worker finishes a task, I give it the next in the queue until the queue is empty.
  • I track time in the web worker to see how much is being used doing the actual compute(e.g. ignoring data transfer overhead).
  • I have an 8 core laptop which runs multi-threaded code daily.

这是我的WebWorker脚本。

Here is my WebWorker script.

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毫秒。主线程在250ms内完成所有工作,所以使用WebWorkers我会慢100%。出于某种原因,在WebWorker中运行的完全相同的代码比在主线程上运行的代码要慢得多。

When the worker logs the time being used, its usually around 130ms per worker, which means the total time is actually almost 500ms. The main thread does all the work in 250ms, so I'm going 100% slower using WebWorkers. For some reason, exactly the same code running in a WebWorker is much much slower than it does on the main thread.

我很快就会有一些工作量可能有数百个任务,所以我希望WebWorkers能够保持我的页面响应。 (目前在大负荷下根本没有)。

Some of the workloads I have soon might have hundreds of tasks, so I was hoping WebWorkers would keep my page responsive. (currently its not at all on big loads).

有人会对我看到如此糟糕的结果有什么建议吗?注意:我已经消除了数据传输的成本(我相信这是最小的)和线程启动。我纯粹是在测量工作人员的计算时间,这很差......有没有人有经验在网络工作者中运行繁重的计算任务?

Would anyone have any suggestions as to why I am seeing such poor results? Note: I have eliminated the cost of data transfer(which I believe to be minimal) and thread startup here. I am purely measuring the compute time in the worker, which is poor... Does anyone have experience running heavy compute tasks in a webworker?

一个想法,就是我我的工作者脚本也加载我的主引擎脚本。 (示例代码中的MyLib.js),这是一个Webpacked脚本,非常大。我使用了这个,所以希望浏览器缓存意味着它不需要再次请求它。也许我应该为webworker上下文生成我的引擎的最小版本。

One idea, is that I my worker script also loads my main engine script. (MyLib.js in the example code), which is a Webpacked script, and quite big. I used this so that hopefully browser caching would mean it doesn't need to request it again. Maybe instead I should generate a minimal version of my engine just for the webworker context.

感谢您的任何提示......

Thanks for any tips...

推荐答案

我现在有了调试了我的工人。

I have now debugged my Worker.

importScripts('../ lib / MyLib.js');

importScripts('../lib/MyLib.js');

最初,我原以为在工作器中重用我的主库js文件会使浏览器使用lib的缓存版本。即浏览器不需要HTTP请求文件,或编译它,因为它已经在内存中。结果证明是错误的,浏览器需要重新请求文件并重新编译它。

Initially, I had thought that re-using my main library js file in the worker would enable the browser to use the cached version of the lib. I.e. the browser would not need to HTTP request the file, or compile it, since it was already in memory. This turns out to be false, and the browser needed to re-request the file and also recompile it.

因为我的脚本非常大,重新编译成了一个很大的开销,因为它似乎也需要为每个线程重新编译它。我通过测量每项任务的往返时间来得出这个结论,同时在工人中执行零工作。每个线程的往返时间开始非常高(300毫秒),并迅速降至<几次迭代后1ms。

Because my script is quite large, recompiling became a big overhead as it also seems to need to re-compile it for each thread. I came to this conclusion by measuring the round trip time for each task, while performing zero work in the worker. The round trip time for each thread started very high (300ms), and quickly dropped to < 1ms after a few iterations.

我现在使用内联Web工作者来避免额外请求并保持我的库封装,如下所述: http://www.html5rocks.com/en/tutorials/workers/basics/#toc-inlineworkers
并且还将工作人员的减少脚本用于最低限度。

I now use an inline web worker to avoid extra requests and keep my library encapsulated, as described here: http://www.html5rocks.com/en/tutorials/workers/basics/#toc-inlineworkers And also use a cut down script for the worker to a bare minimum.

我现在的表现非常出色。什么是250毫秒~50毫秒。第一次往返很慢,但也不算太差,并且网上工作人员的内联速度要快得多。

I now am getting excellent performance. ~50ms for what was 250ms. The first round trip is slow, but not too bad, and inlining the web worker made it a lot faster.

这篇关于WebWorkers执行似乎比主线程慢得多的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆