Is multithreading with webworkers ineffective?

2019-02-19 13:04发布

问题:

I have a project in which I have to process quite large objects, each taking about 500ms. I thought that using web workers would greatly speed up this process. But after playing around with web workers, they didn't seem to improve the speed at all - even if I took away the preprocessing the creation of the web workers.

So I decided to create a simple example: there is an array with N numbers, and the sum of those numbers should be calculated.

So first, without webworkers (DEMO):

/** Goal: return sum of all numbers in array */
var numbers = [];

for(var i = 0; i < N; i++){
    numbers.push(Math.floor(Math.random() * 100));
}

/** Test without web workers */
var total = 0;
for(var i = 0; i < numbers.length; i++){
    total += numbers[i];
}

Then, with webworkers (DEMO):

/** Options */
var WORKERS = 5; // N should be divisble by WORKERS

/** Test WITH web workers */
var workers = [];

var source = `
onmessage = function(e) {
    var total = 0;
    for(var i = 0; i < e.data.length; i++){
    total += e.data[i];
  }
    postMessage(total);
}`

for(var i = 0; i < WORKERS; i++){
  var blob = new Blob([source]);
  var blobURL = window.URL.createObjectURL(blob);
  let worker = new Worker(blobURL);

  worker.onmessage = function(e){
    total += e.data;
    worker.terminate();
    if(++finished == workers.length) done();
  }

  workers.push(worker);
}

var finished = 0;
var chunk = Math.floor(N / WORKERS);

var sliced = [];
for(var i = 0; i < workers.length; i++){
    sliced.push(numbers.slice(i*chunk,i*chunk+chunk));
}

// we calculate time after we created the workers, from here
var total = 0;
for(var i = 0; i < workers.length; i++){
  workers[i].postMessage(sliced[i]);
}

function done(){
  // do something
}

So the results: webworkers seem to be completely disastrous. It's over 10x slower than without webworkers.

So my question, can anyone show me an example where multithreading with webworkers is actually faster? I'm failing to see the point of webworkers besides running without affecting the UI....

Edit: it runs over way slower, but the CPU usage is way higher (100% with, ~30% without webworkers) - it makes me question where all that power is going to

Edit 2: Even when you leave the onmessage on the worker side do nothing, it still runs way slower... it seems like the communication between the main thread and the worker thread is just incredibly slow (see for yourself)

Edit 3: it's not related to postMessage, I have measured performance and it's nothing I can do about by coding differently. The weirdest thing of all: when I measure performance with Google chrome dev tools, it runs almost 2x as fast

Interesting article:

回答1:

Your benchmark is being swamped by the cost of transferring ten million numbers to each worker.

Instead, create a ArrayBuffer. Pass that, as part of transferList (the second parameter to postMessage). On my machine the workers run this job in less than 100ms compared to 200ms without the workers.

See https://jsfiddle.net/ooduhb5h/7/.