I'm experimenting with web workers, and was wondering how well they would deal with embarassingly parallell problems. I therefore implemented Connaway's Game of Life. (To have a bit more fun than doing a blur, or something. The problems would be the same in that case however.)
At the moment I have one web worker performing iterations and posting back new ImageData for the UI thread to place in my canvas. Works nicely.
My experiment doesn't end there however, cause I have several CPU's available and would like to parallellize my application.
So, to start off simply I split my data in two, down the middle, and make two workers each dealing with a half each. The problem is of course the split. Worker A needs one column of pixels from worker B and vice versa. Now, I can clearly fix this by letting my UI-thread give that column down to the workers, but it would be much better if my threads could pass them to eachother directly.
When splitting further, each worker would only have to keep track of it's neighbouring workers, and the UI thread would only be responsible for updating the UI (as it should be).
My problem is, I don't see how I can achieve this worker-to-worker communication. I tried handing the neighbours to eachother by way of an initialization postMessage, but that would copy my worker rather than hand down a reference, which luckily chrome warned me about being impossible.
Uncaught Error: DATA_CLONE_ERR: DOM Exception 25
Finally I see that there's something called a SharedWorker. Is this what I should look into, or is there a way to use the Worker that would solve my problem?
You should be able to use channel messaging:
var channel = new MessageChannel();
worker1.postMessage({code:"port"}, [channel.port1]);
worker2.postMessage({code:"port"}, [channel.port2]);
Then in your worker threads:
var xWorkerPort;
onmessage = function(event) {
if (event.data.code == "port") {
xWorkerPort = event.ports[0];
xWorkerPort.onmessage = function(event) { /* do stuff */ };
}
}
There's not much documentation around, but you could try this MS summary to get started.
Related
As is known, we can't access the dom element from the workers. When I create AudioContext:
var audioCtx = new (canvas.AudioContext || canvas.webkitAudioContext)();
I get:
Uncaught ReferenceError: window is not defined
Is there any way to walk around this problem?
Not yet no. Here is a specs issue discussing this very matter, and it is something a lot of actors would like to see, so there is hope it comes, one day.
Note that there is an AudioWorklet API available, which will create its own Worklet (which also works in a parallel thread), but you still need to instantiate it from the UI thread, and you don't have access to everything that can be done in an AudioContext. Still, it may suit your needs.
Also, note that it might be possible to do the computing you have to do in a Worker already, by transferring ArrayBuffers from your UI thread to the Worker's one, or by using SharedArrayBuffers.
I can assure you, this is not your typical "how to watch for changes on a JS variable" post!
So I have some worker threads gathering data for a parent thread in Node.js.
The parent thread processes the data in ticks of a set timeframe, just keeping a general eye on things.
Occasionally the data the worker threads send to the parent thread is really interesting, and when the parent thread gets interesting data I want it to be processed immediately. (Without waiting for the next tick to roll around.)
What I am stuck on is how to most quickly and efficiently communicate to the main worker thread that dataIsInteresting = true.
The worker threads know that their data is interesting immediately, but the main thread only knows that when it processes it's tick a few hundred milliseconds later generally.
I am using SharedArrayBuffers to share memory between the worker threads and the parent thread.
The frustrating thing is that the parent thread ACTUALLY HAS THE INTERESTING DATA IMMEDIATELY, it's in there, it just doesn't know it until the timer goes off and tells it to process the data in that SharedArrayBuffer.
I know I can send a message from a worker thread to a parent thread in a number of ways, but that takes about 0.75ms no matter how I do that. (Speed seems to be the same for JS postMessage, as well as a local Websocket client/server setup... which makes sense.)
Which is fine, but I've found a much faster way to communicate (that, at least) between threads and just hoping there may be others I have not thought of?
I can run a recursive loop of the same function called isDataInteresting() inside the parent thread, constantly calling itself with process.nextTick(() => {isDataInteresting();});, but that maxes out the CPU and I worry that it will slow down other important calculations that need to happen regularly in the parent thread.
I can switch it up calling setTimeout(function(){isDataInteresting();},0); every few thousand calls to isDataInteresting() to cut the CPU usage down to a constant 25% on the parent thread which is the route I am probably going to take but that just seems so kludgy.
I can't pass off the aggressive isDataInteresting() check to another worker thread as that creates the same problem I had in the first place... which is how to inform the parent thread of interesting data immediately!
Proxy objects are not allowed to be cloned/posted via javascript postMessages unfortunately either.
The isDataInteresting() check is the fastest by a large margin. With the parent thread being notified of interesting data in about 10,000 nanoseconds as opposed to 750,000 nanoseconds. So if the kludge is the only thing that works, I guess I'll take it.
Is there another way to check for updated data on a variable that I am not considering, I hope?
Thanks for reading!
I have a performance problem in Javascript causing a crash lately at work. With the objective modernising our applications, we are looking into running our applications as webservers, onto which our client would connect via a browser (chrome, firefox, ...), and having all our interfaces running as HTML+JS webpages.
To give you an overview of our performance needs, our application run image processing from camera sources, running in some cases at more than 20 fps, but in the most case around 2-3fps max.
Basically, we have a Webserver written in C++, which HTTP requests, and provides the user with the HTML pages of the interface and the corresponding JS scripts of the application.
In order to simplify the communication between the two applications, I then open a web socket between the webpage and the c++ server to send formatted messages back and forth. These messages can be pretty big, up to several Mos.
It all works pretty well as long as the FPS stays relatively low. When the fps increases the following two things happen.
Either the c++ webserver memory footprint increases pretty fast and crashes when no more memory is available. After investigation, this happens when the network usage full, and the websocket cache fills up. I think this is due to the websocket TCP-IP way of doing stuff, as the socket must wait for the message to be sent and received to send the next one.
Or the browser crashes after a while, showing the Aw snap screen (see figure below). It seems in that case that the same thing more or less happen but it seems this time due to the garbage collection strategy. The other figure below shows the printscreen of the memory usage when the application is running, clearly showing saw pattern. It seems to indicate that garbage collection is doing its work at intervals that are further and further away.
I have trapped the problem down to very big messages (>100Ko) being sent at fast rate per second. And the bigger the message, the faster it happens. In order to use the message I receive, I start a web worker, pass the blob i received to the web worker, the webworker uses a FileReaderSync to convert the message as an ArrayBuffer, and passes it back to the main thread. I expect this to have quite a lot of copies under the hood, but I am not so well versed in JS yet so to be sure of this statement. Also, I initialy did the same thing without the webworker (FileReader), but the framerate and CPU usage were really bad...
Here is the code I call to decode the messages:
function OnDataMessage(msg)
{
var webworkerDataMessage = new Worker('/js/EDXLib/MessageDecoderEvent.js'); // please no comments about this, it's actually a bit nicer on the CPU than reusing the same worker :-)
webworkerDataMessage.onmessage = MessageFileReaderOnLoadComManagerCBack;
webworkerDataMessage.onerror=ErrorHandler;
webworkerDataMessage.postMessage(msg.data);
}
function MessageFileReaderOnLoadComManagerCBack(e)
{
comManager.OnDataMessageReceived(e.data);
}
and the webworker code:
function DecodeMessage(msg)
{
var retMsg = new FileReaderSync().readAsArrayBuffer(msg);
postMessage(retMsg);
}
function receiveDecodingRequest(e)
{
DecodeMessage(e.data);
}
addEventListener("message", receiveDecodingRequest, true);
My question are the following:
Is there a way to make the GC not have to collect so much memory, by for instance telling some of the parts I use to reuse buffers instead of recreating them, or keeping the GC work intervals fixed ? This is something I know how to do in C++, but in JS ?
Is there another method I should use for my big payloads? Keep in mind that the transmission should be as fast as possible.
Is there another method for reading blob data as arraybuffers that would faster than what I did?
I thank you in advance for you help/comments.
As it turns out, the memory problem was due to the new WebWorker line and the new FileReaderSync line in the WebWorker.
Removing these greatly improved the performances!
Also, it turns out that this decoding operation is not necessary if I want to use the websocket as array buffer. I just need to set the binaryType attribute of websockets to "arraybuffer"...
So all in all, a very simple solution to a pain in the *** problem :-)
I need to display a quite complex 2D shape in a canvas using PixiJS and to do so I'd like to create and define all graphic elements in a separate thread (web worker) to not block the rest of the UI.
The problem is that when I import PixiJS in the web worker file like this
importScripts('https://cdnjs.cloudflare.com/ajax/libs/pixi.js/4.5.2/pixi.js');
it gives me an error because it accesses DOM elements (like window and document) and this is not allowed in web workers. How can I solve this?
This is the error:
Uncaught ReferenceError: window is not defined
at Object.179../Math.sign (Object.assign.js:3)
at s (_prelude.js:1)
at _prelude.js:1
at Object.<anonymous> (WebGLPrepare.js:101)
at Object.187../accessibility (index.js:44)
at s (_prelude.js:1)
at e (_prelude.js:1)
at _prelude.js:1
at _prelude.js:1
at _prelude.js:1
Well I guess you cannot. Webworkers have their own DedicatedWorkerGlobalScope with no access to the DOM, window, etc. If you have heavy computations, for instance to calculate animations, all you can do is let the webworker do the number crunching and the main thread do the rendering.
The Worker and the main thread cannot share objects. Even if the following explanation is not 100% technically correct, you can imagine that if you:
var obj = { a: { b: 100 } };
worker.postMessage(obj);
It will be more like:
//really dirty object clone here
worker.postMessage(JSON.parse(JSON.stringify(obj)));
With that I want to point out, that you cannot share objects with the worker and vice verca.
Find a tecnically correct explaintion here:
https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#Transferring_data_to_and_from_workers_further_details
Philipp is right on his answer, I just want to elaborate this a bit further, from the games and web workers point-of-view.
In my experience, it is ofter hard to take advantage of web workers in games. Especially if you use a library to handle canvas / webGL, since that does most of the number crunching anyway. Web workers are designed for number crunching as philipp mentioned. And passing data between web worker and main thread is quite expensive, so passing data and doing tiny operations on them, will not be beneficial.
Without providing a direct link, I read already long while ago that some game engines (I think construct) used web workers for their pathfinding module. So nothing related to direct graphic handling, but numerical operations.
Also there is a proposal for possibility to use canvases in web worker contexts, so it is clearly an issue with others too. If my memory serves right, I believe it was this: https://developer.mozilla.org/fi/docs/Web/API/OffscreenCanvas
You can include PixiJS in your Web Worker, although you can not perform graphics operations.
Although the other two answers are technically correct, there are legitimate use cases for including Pixi's code in your Worker's scope without actually rendering graphics. An example is using Pixi's Point and Rectangle classes. In my case, I wrote several modules that rely on definitions exported by Pixi and perform heavy calculations based on them.
The errors you had were because Pixi relies on the globals window and document to define some graphics-related constants. In order to allow Pixi to finish loading you can provide mock values for window and document with empty methods with the same names as the ones used by Pixi.
As an example, while using PixiJS 4.8.6 the following code worked for me:
window = self
document = {
createElement () {
return {
getContext () {
return {
fillRect () {},
drawImage () {},
getImageData () {},
}
},
}
},
}
importScripts('pixi-4-8-6.js');
/* Web Worker code follows */
// ...
Depending on Pixi's version you may need to adjust this boilerplate. An alternative would be to try one of those packages that mock document and Canvas for headless browsers. I haven't tried that since the code above worked well enough.
Pixi 5 came out recently and it may have changed this completely. I skimmed the code and it looks like they removed the constant definition that was causing problems so it's also possible that this new version just works out of the box. I know they have been looking into letting people use Workers more easily and they have been exploring OffscreenCanvas like Hachi said.
pixi team is working on adding headless environments support like web workers; see https://github.com/pixijs/pixijs/issues/7123
So I have this seriously recursive function that I would like to use with my code. The issue is it doesn't really take advantage of dual core machines because js is single threaded. I have tried using webworkers but don't really know much about multicore programming. Would someone point me to some material that could explain how it is done. I googled to find this sample link but its not really much help without documentation! =/
I would be glad if someone could show me how this could be done without webworkers though! That would be just awesome! =)
I came across this link on whatwg. This is really weird because it explains how to use multicore programming in webworkers etc, but on executing on my chrome browser it throws errors. Same goes with other browsers.
Error: 9Uncaught ReferenceError: Worker is not defined in worker.js
UPDATE (2018-06-21): For people coming here in search of multi-core programming in JavaScript, not necessarily browser JavaScript (for that, the answer still applies as-is): Node.js now supports multi-threading behind a feature flag (--experimental-workers): release info, relevant issue.
Writing this off the top of my head, no guarantees for source code. Please go easy on me.
As far as I know, you cannot really program in threads with JavaScript. Webworkers are a form of multi-programming; yet JavaScript is by its nature single-threaded (based on an event loop).
A webworker is seperate thread of execution in the sense that it doesn't share anything with the script that started it; there is no reference to the script's global object (typically called "window" in the browser), and no reference to any of your main script's variables other than data you send to the thread.
Think as the web worker as a little "server" that gets asked a question and provides an answer. You can only send strings to that server, and it can only parse the string and send back what it has computed.
// in the main script, one starts a worker by passing the file name of the
// script containing the worker to the constructor.
var w = new Worker("myworker.js");
// you want to react to the "message" event, if your worker wants to inform
// you of a result. The function typically gets the event as an argument.
w.addEventListener("message",
function (evt) {
// process evt.data, which is the message from the
// worker thread
alert("The answer from the worker is " + evt.data);
});
You can then send a message (a String) to this thread using its postMessage()-Method:
w.postMessage("Hello, this is my message!");
A sample worker script (an "echo" server) can be:
// this is another script file, like "myworker.js"
self.addEventListener("message",
function (evt) {
var data = JSON.parse(evt.data);
/* as an echo server, we send this right back */
self.postMessage(JSON.stringify(data))
})
whatever you post to that thread will be decoded, re-encoded, and sent back. of course you can do whatever processing you would want to do in between. That worker will stay active; you can call terminate() on it (in your main script; that'd be w.terminate()) to end it or calling self.close() in your worker.
To summarize: what you can do is you zip up your function parameters into a JSON string which gets sent using postMessage, decoded, and processed "on the other side" (in the worker). The computation result gets sent back to your "main" script.
To explain why this is not easier: More interaction is not really possible, and that limitation is intentional. Because shared resources (an object visible to both the worker and the main script) would be subject to two threads interfering with them at the same time, you would need to manage access (i.e., locking) to that resource in order to prevent race conditions.
The message-passing, shared-nothing approach is not that well-known mainly because most other programming languages (C and Java for example) use threads that operate on the same address space (while others, like Erlang, for instance, don't). Consider this:
It is really hard to code a larger project with mutexes (a mutual exclusion mechanism) because of the associated deadlock/race condition complexities. This is stuff that can make grown men cry!
It is really easy in comparison to do message-passing, shared-nothing semantics. The code is isolated; you know exactly what goes into your worker and what comes out of your worker. Deadlocks and race conditions are impossible to achieve!
Just try it out; it is capable of doing interesting things, probably all you want. Bear in mind that it is still implementation defined whether it takes advantage of multicore as far as I know.
NB. I just got informed that at least some implementations will handle JSON encoding of messages for you.
So, to give an answer to your question (it's all above; tl;dr version): No, you cannot do this without web workers. But there is nothing really wrong about web workers aside from browser support, as is the case with HTML5 in general.
As far as I remember this is only possible with the new HTML5 standard. The keyword is "Web-Worker"
See also:
HTML5: JavaScript Web Workers
JavaScript Threading With HTML5 Web Workers
Web workers are the answer to the client side. For NodeJS there are many approaches. Most popular - spawn several processes with pm2 or similar tool. Run single process and spawn/fork child processes. You can google around these and will find a lot of samples and tactics.
Web workers are already well supported by all browsers. https://caniuse.com/#feat=webworkers
API & samples: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers