Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web workers terminating abruptly

I initiated a web worker on chrome and it had a simple function that was called repeatedly using setTimeout. Surprisingly the web worker terminated after the function was called around 1000 times. Can anyone explain why? I guess chrome is doing some optimization.

webworker.js

function hi() {
    postMessage('1');
    setTimeout(hi, 1);
}
hi();

main.js

var blob = new Blob([code]);
var blobURL = window.URL.createObjectURL(blob);
var worker = new Worker(blobURL);
worker.onmessage = function(data) {
    console.log(data.data); // gets called around 1000 times and done
};

EDIT: Reproduced in a fiddle: http://jsfiddle.net/meovfpv3/1/ It seems to takes arbitrarily long for the onmessage callback to stop firing, as quickly as a few seconds and as long as +5 mins

like image 818
Faiz Halde Avatar asked May 08 '16 11:05

Faiz Halde


People also ask

Can a web worker terminate itself?

Terminating a Worker We can kill a worker's task by using the terminate() function or have it terminate itself by calling the close() function on self. This helps reduce the memory consumption for other applications on the user's computer.

What method cancels web worker?

terminate() The terminate() method of the Worker interface immediately terminates the Worker .

How can you tell if a Webworker has been terminated?

The only solution would be to override both Worker. terminate() and DedicatedWorkerGlobalScope. close() in order for these to let you know about it.

How can you end a web worker that is running beyond expected time?

Web Workers don't stop by themselves but the page that started them can stop them by calling terminate() method. worker. terminate(); A terminated Web Worker will no longer respond to messages or perform any additional computations.


1 Answers

Here is my best guess at what is happening. By posting a message from the Web Worker every 1ms, you are demanding that the main thread processes each posted message within 1ms.

If the main thread isn't able to process the message within 1ms, you are still sending it a new message even though it isn't finished processing the last message. I would imagine this puts it into a queue of messages waiting to be processed.

Now since you are sending messages from the web worker faster than they can be processed, this queue of unprocessed messages is going to get bigger and bigger. At some point Chrome is going to throw up its hands and say "There are too many messages in the queue", and instead of queueing new messages for processing, it drops them.

This is why if you use a reasonable number in your timeout like 100ms, the message has plenty of time to be processed before the next message is sent, and no problem with unprocessed messages occurs.


I've created a jsFiddle where the worker sends a message to the main thread, and the main thread sends the message back to the worker. If that process doesn't happen before the next message is sent, the counters in both threads will be mismatched and the web worker will terminate.

http://jsfiddle.net/meovfpv3/3/

You can see that with a reasonable setTimeout of 100ms, all messages have adequate time to process before the next message occurs.

When you lower the setTimeout to 1ms, the message chain doesn't have time to finish before the next message is sent and the counters in each thread become eventually desynced, tripping the if clause and terminating the web worker.


One way to fix this problem is instead of blindly posting a message every 1ms whether the last one has been processed or not, only post a new message after you have received a message back from the main thread. This means that you are only posting messages as fast as the main thread can process them.


For completeness here is a copy of the JSFiddle code:

Worker:

  var counter2 = 0;
  var rcvd = true;
  function hi() {
    counter2++;
    console.log("")
    console.log("postMessage", counter2)
    postMessage(counter2);
    if (!rcvd) {
        self.close();
      console.log("No message received");
    }
    rcvd = false;
    setTimeout(hi, 1);
  }
  hi();
  onmessage = function(e) {
    rcvd = true;
    console.log("secondMessage", e.data);
  }

Main:

var ww = document.querySelector('script[type="text/ww"]'),
    code = ww.textContent,
    blob = new Blob([code], {type: 'text/javascript'}),
    blobUrl = URL.createObjectURL(blob),
    worker = new Worker(blobUrl),
    counter = 0;

worker.onmessage = function(e) {
    counter++;
  console.log("onmessage:", counter);
  worker.postMessage(e.data);
}
like image 104
Maximillian Laumeister Avatar answered Oct 17 '22 09:10

Maximillian Laumeister