javascript - WebWorkers execution appears to be much slower than the main thread - Stack Overflow

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

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

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

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.

  • 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 pute(e.g. ignoring data transfer overhead).
  • I have an 8 core laptop which runs multi-threaded code daily.

Here is my WebWorker script.

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

let timeComputing = 0;  
this.onmessage = function(e) {
  switch (e.data.msg) {
    case 'pute':
        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);
  }
}

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.

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 pute time in the worker, which is poor... Does anyone have experience running heavy pute tasks in a 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 been working on optimizing some long running JAvaScript, and tried implementing WebWorkers.

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

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.

  • 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 pute(e.g. ignoring data transfer overhead).
  • I have an 8 core laptop which runs multi-threaded code daily.

Here is my WebWorker script.

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

let timeComputing = 0;  
this.onmessage = function(e) {
  switch (e.data.msg) {
    case 'pute':
        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);
  }
}

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.

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 pute time in the worker, which is poor... Does anyone have experience running heavy pute tasks in a 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...

Share Improve this question asked Sep 9, 2016 at 20:16 Philip TaylorPhilip Taylor 5395 silver badges11 bronze badges 2
  • If the workers are truly independent and working on different threads, wouldn't the total time be closer to 130ms, rather than 4 * 130ms? – Heretic Monkey Commented Sep 9, 2016 at 20:26
  • Thanks Akshat. I have worked hard to ensure that all my data is in 'transferable' types and passed as transferables. My timing numbers only include execution time, not transfer + execution time. (see the provided sample code running in the Worker)<br> Re: Mike: Yes, even though the code is running slower, it should only total ~130ms, but the time I measure for all the tasks to plete is ~500ms. This indicates I am spending significant time in data transfer. Something to look into, but not the main issue I am debugging. (Maybe I am incorrect here) – Philip Taylor Commented Sep 9, 2016 at 20:40
Add a ment  | 

1 Answer 1

Reset to default 7

I have now debugged my Worker.

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

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 pile it, since it was already in memory. This turns out to be false, and the browser needed to re-request the file and also repile it.

Because my script is quite large, repiling became a big overhead as it also seems to need to re-pile 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.

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

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.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1742251127a4409172.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信