JavaScript and Threads

JavaScript and Threads

See http://caniuse.com/#search=worker for the most up-to-date support info.

The following was the state of support circa 2009.


The words you want to google for are JavaScript Worker Threads

Apart from from Gears there's nothing available right now, but there's plenty of talk about how to implement this so I guess watch this question as the answer will no doubt change in future.

Here's the relevant documentation for Gears: WorkerPool API

WHATWG has a Draft Recommendation for worker threads: Web Workers

And there's also Mozilla’s DOM Worker Threads


Update: June 2009, current state of browser support for JavaScript threads

Firefox 3.5 has web workers. Some demos of web workers, if you want to see them in action:

  • Simulated Annealing ("Try it" link)
  • Space Invaders (link at end of post)
  • MoonBat JavaScript Benchmark (first link)

The Gears plugin can also be installed in Firefox.

Safari 4, and the WebKit nightlies have worker threads:

  • JavaScript Ray Tracer

Chrome has Gears baked in, so it can do threads, although it requires a confirmation prompt from the user (and it uses a different API to web workers, although it will work in any browser with the Gears plugin installed):

  • Google Gears WorkerPool Demo (not a good example as it runs too fast to test in Chrome and Firefox, although IE runs it slow enough to see it blocking interaction)

IE8 and IE9 can only do threads with the Gears plugin installed

Why doesn't JavaScript support multithreading?

JavaScript does not support multi-threading because the JavaScript interpreter in the browser is a single thread (AFAIK). Even Google Chrome will not let a single web page’s JavaScript run concurrently because this would cause massive concurrency issues in existing web pages. All Chrome does is separate multiple components (different tabs, plug-ins, etcetera) into separate processes, but I can’t imagine a single page having more than one JavaScript thread.

You can however use, as was suggested, setTimeout to allow some sort of scheduling and “fake” concurrency. This causes the browser to regain control of the rendering thread, and start the JavaScript code supplied to setTimeout after the given number of milliseconds. This is very useful if you want to allow the viewport (what you see) to refresh while performing operations on it. Just looping through e.g. coordinates and updating an element accordingly will just let you see the start and end positions, and nothing in between.

We use an abstraction library in JavaScript that allows us to create processes and threads which are all managed by the same JavaScript interpreter. This allows us to run actions in the following manner:

  • Process A, Thread 1
  • Process A, Thread 2
  • Process B, Thread 1
  • Process A, Thread 3
  • Process A, Thread 4
  • Process B, Thread 2
  • Pause Process A
  • Process B, Thread 3
  • Process B, Thread 4
  • Process B, Thread 5
  • Start Process A
  • Process A, Thread 5

This allows some form of scheduling and fakes parallelism, starting and stopping of threads, etcetera, but it will not be true multi-threading. I don’t think it will ever be implemented in the language itself, since true multi-threading is only useful if the browser can run a single page multi-threaded (or even more than one core), and the difficulties there are way larger than the extra possibilities.

For the future of JavaScript, check this out:
https://developer.mozilla.org/presentations/xtech2006/javascript/

Javascript and its one single thread

It helps to understand that there is a call stack and an event queue. Call stack processes one thing at a time and represents the single threaded nature of JavaScript. The event loop is sort of queue where asyschronus methods are placed and then moved to call stack for processing when they are complete and when the call stack is empty.

Question: it has to wait for the single thread to end the execution of the first callback method, right?

Answer: Yes that is correct.

Question: Its impossible then that the code for the callback method it being executed at the same time for two threads.

Answer: Yes that's also correct

Question: Its like having the functionality synchronized from java in javascript for methods

Answer: That's not correct becasue of event loop and call stack.

Do check out this video https://www.youtube.com/watch?v=8aGhZQkoFbQ on youtube for a detailed explanation.

Is Node.js considered multithreading with worker threads?

This makes it sound like JavaScript was actually using multiple different threads the entire time. Why are people calling JavaScript single threaded?

The programming model in Node.js is a single threaded event loop with access to asynchronous operations that use native code to implement asynchronous behavior for some operations (disk I/O, networking, timers, some crypto operations, etc...).

Also, keep in mind that this programming model is not a product of JavaScript the language itself. It's a product of how JavaScript is deployed in popular environments like Node.js and browsers as an event-driven implementation.

The fact that internally there is a native code thread pool that is used for the implementation of some asynchronous operations such as file I/O or some crypto operations does not change the fact that the programming model is a single threaded event loop. The thread pool is just how the implementation of a time consuming task is made to have an asynchronous interface through JavaScript. It's an implementation detail that doesn't change the JavaScript programming model from a single threaded, event loop model.

Similarly, the fact that you can now actually create WorkerThreads does not really change the primary programming model either because the WorkerThreads run in a separate JavaScript VM with a separate event loop and do not share regular variables. So, whether you're using WorkerThreads or not, you still pretty much design your code for an event-driven, non-blocking system.

WorkerThreads do allow you to off-load some time-consuming tasks to get them out of the main event loop to keep that main event loop more responsive and this is a very good and useful option to have in some cases. But, the overall model does not change. For example, all networking is still event driven and non-blocking, asynchronous. So, just because we have WorkerThreads, that doesn't mean that you can now program networking in JavaScript like you sometimes do in Java with a separate thread for every new incoming request. That part of JavaScript's model doesn't change at all. If you have an HTTP server in Node.js, it's still receiving one incoming request at a time and won't start processing the next incoming request until that prior incoming request returns control back to the event loop.

Also, you should be aware that the current implementation of WorkerThreads in Node.js is fairly heavyweight. The creation of a WorkerThread fires up a new JavaScript VM, initializes a new global context, sets up a new heap, starts up a new garbage collector, allocates some memory, etc... While useful in some cases, these WorkerThreads are much, much more heavyweight than an OS level thread. I think of them as if they're almost like mini child processes, but with the advantage that they can use SharedMemory between WorkerThreads or between the main thread and WorkerThreads which you can't do with actual child processes.

Or is JavaScript indeed permanently single threaded, but with the power of worker threads, a process is able to have multiple threads of JavaScript, which still behave single thread?

First off, there's nothing inherent in the JavaScript language specification that requires single threaded. The single-threaded programming model is a product of how the JavaScript language is implemented in the popular programming environments such as Node.js and the browser. So, when speaking about single-threadedness, you should speak about the programming environment (such as Node.js), not about the language itself.

In Node.js, a process is able to have multiple threads of JavaScript now (using WorkerThreads). These run independently so you can get true parallelization of running JavaScript in multiple threads concurrently. To avoid many of the pitfalls of thread synchronization, WorkerThreads run in a separate VM and do not share access to variables of other WorkerThreads or the main thread except with very carefully allocated and controlled SharedMemory buffers. WorkerThreads would typically communicate with the main thread using message passing which runs through the event loop (so a level of synchronization is forced on all the JavaScript threads that way). Messages are not passed between threads in a pre-emptive way - these communication messages flow through the event loop and have to wait their turn to be processed just like any other asynchronous operation in Node.js.

Here's an example implementation using WorkerThreads. I was writing a test program whose job it was to run a simulation of an activity several billion times and record statistics on all the results to see how random the results were. Some parts of the simulation involved some crypto operations that were pretty time consuming on the CPU. In my first generation of the code, I was running a smaller number of iterations for testing, but it was clear that the desired several billions iterations was going to take many hours to run.

Through testing and measurement, I was able to find out which parts of the code were using the most CPU and then I created a WorkerThread pool (8 worker threads) that I could pass the more time consuming jobs to and they could work on them in parallel. This reduced the overall time of running the simulation by a factor of 7.

Now, I could have also used child processes for this, but they would have been less efficient because I needed to pass large buffers of data between the main thread and a workerThread (the workerThread was processing data in that buffer) and it was a lot more efficient to do that using a SharedArrayBuffer than it would be to pass the data between parent and child processes (which would have involved copying the data rather than sharing the data).

Is Javascript async and await the equivalent to mulithreading?

Is using async and await the crude person's threads?

No, not at all. It's just syntax sugar (really, really useful sugar) over using promises, which in turn is just a (really, really useful) formalized way to use callbacks. It's useful because you can wait asynchronously (without blocking the JavaScript main thread) for things that are, by nature, asynchronous (like HTTP requests).

If you need to use threads, use web workers, Node.js worker threads, or whatever multi-threading your environment provides. Per specification (nowadays), only a single thread at a time is allowed to work within a given JavaScript "realm" (very loosely: the global environment your code is running in and its associated objects, etc.) and so only a single thread at a time has access to the variables and such within that realm, but threads can cooperate via messaging (including transferring objects between them without making copies) and shared memory.

For example:

async function isThisLikeTwoThreads() {
const a = slowFunction();
const b = fastFunction();
console.log(await a, await b);
}

Here's what that code does when isThisLikeTwoThreads is called:

  1. slowFunction is called synchronously and its return value is assigned to a.
  2. fastFunction is called synchronously and its return value is assigned to b.
  3. When isThisLikeTwoThreads reaches await a, it wraps a in a promise (as though you did Promise.resolve(a)) and returns a new promise (not that same one). Let's call the promise wrapped around a "aPromise" and the promise returned by the function "functionPromise".
  4. Later, when aPromise settles, if it was rejected functionPromise is rejected with the same rejection reason and the following steps are skipped; if it was fulfilled, the next step is done
  5. The code in isThisLikeTwoThreads continues by wrapping b in a promise (bPromise) and waiting for that to settle
  6. When bPromise settles, if it was rejected functionPromise is rejected with the same rejection reason; if it was fulfilled, the code in isThisLikeTwoThreads continues by logging the fulfillment values of aPromise and bPromise and then fulfilling functionPromise with the value undefined

All of the work above was done on the JavaScript thread where the call to isThisLikeTwoThreads was done, but it was spread out across multiple "jobs" (JavaScript terminology; the HTML spec calls them "tasks" and specifies a fair bit of detail for how they're handled on browsers). If slowFunction or fastFunction started an asynchronous process and returned a promise for that, that asynchronous process (for instance, an HTTP call the browser does) may have continued in parallel with the JavaScript thread while the JavaScript thread was doing other stuff or (if it was also JavaScript code on the main thread) may have competed for other work on the JavaScript thread (competed by adding jobs to the job queue and the thread processing them in a loop).

But using promises doesn't add threading. :-)

Is JavaScript single threaded?

Javascript isn't inherently single-threaded or multi-threaded as a language. There are Javsacript environments that don't offer Javascript threads and environments that do offer Javascript threads. The language itself doesn't specify single-threadedness or multi-threadedness. Instead, it's up to the environment whether it wants to make threads of Javascript available.

So, to your specific question:

Is JavaScript single threaded?

No. It's not specifically single threaded or multiple threaded. The language specification doesn't require either. The threading of Javascript is up to the run-time environment to implement. It so happens that both the browser and node.js started out without Javascript threads and an event-driven architecture which led to this notion that there are no threads in a Javascript environment, but there ARE. They now both offer Javascript threads (WebWorkers in the browser and WorkerThreads in node.js).

The Javascript specification offers some features that are useful in multi-threaded environments such as SharedArrayBuffer objects and Atomics and environments that offer threading provide additional libraries. So, the current language specification recognizes some of the needs of multi-threading and provides some tools for it, though there is no specific requirement that a Javascript runtime has or doesn't have threads. It's up to the run-time whether they want to offer that capability to run multiple Javascript threads of execution in parallel or not.

Javascript: How multiple threads are implemented in javascript?

A JavaScript program runs on a single thread of execution using a "run to completion" semantic.

Operations that would normally block in other languages are non-blocking, and simply handed off to the host (in this case, the browser), with your program notified of progress asynchronously via events.

When the host raises an event to be consumed by your program (eg. an inbound message), it puts a notification of that event in a queue as a "job". When that job reaches the front of the queue, and as soon as the call stack is empty (ie. the current script being run has run to completion), the JavaScript runtime dequeues the job and invokes the continuation function associated with it (ie. the part of your program configured to handle the event).

Your game will be sending messages over the network (eg via WebSocket). Your program will simply hand each message to the browser. This process is not computationally expensive or time consuming. The browser is multithreaded and will handle the low-level and time consuming networking concerns for you.

JavaScript is an event-based language. If you wish to be notified of future events related to a message you sent, then you can supply a callback (or use a promise) to be invoked by the runtime in the future at the appropriate time, rather than simply waiting for it. In this way the time available on the main thread of execution is used efficiently.

Your game loop will probably use requestAnimationFrame. That gives you about 16 milliseconds of computation per frame. Computation of game state might take a few milliseconds. Handling scheduled and time-based events might take another few milliseconds. Finally rendering needs some time too. In effect your program cooperatively multi-tasks on a single thread of execution.

For long-running, computationally expensive tasks you can use the Worker API to create new threads of execution with which you can communicate in a controlled way, but you will probably not need this here.

There is plenty of information online already about this topic. Search for "how the event loop works".

Relevant questions here, here, here, here, and here.

Threads vs Async on threaded languages such as C#?

Asynchrony and multithreading are both forms of concurrency:

  • Concurrency: doing more than one thing at a time.
  • Asynchrony: starting an operation and freeing up the current thread to do other things until that operation completes.
  • Parallelism / multithreading: using multiple threads to do multiple things at the same time.

I was looking at the difference between JavaScript's single-threaded asynchronous processing and C#'s threaded approach to asynchronous processing

I believe that my answer to that question misled you a bit. When I talk about "asynchronously multi-threaded", I mean that the asynchrony exists within a multi-threaded environment. I do not mean that the asynchrony is implemented using multi-threading.

JavaScript is (for now) locked into a single-threaded model (setting aside for the moment things like web workers which are kind of like threads). So, asynchrony is naturally done all on a single thread. Note that pure asynchrony does not require a thread for the asynchronous operation; e.g., when you do a web API call, there's no thread that has to sit, waiting for the response to come back. Node.js (and browser JavaScript for that matter) use similar techniques to the ones in my post There Is No Thread, plus a threadpool to wrap a small number of blocking APIs.

The important thing to note here is that asynchrony does not require a thread. It is a form of concurrency that can be threadless, in principle. On the server side, this permits a great degree of scalability.

JavaScript stops there, at least for now. Node.js scales quite well on a single thread (not counting the thread pool), since it enforces asynchrony. ASP.NET takes a different approach: asynchrony has historically been a pain to use, so ASP.NET multi-threads first and then allows asynchronous or synchronous code; modern services can use asynchrony in that multi-threaded environment for even more scalability.

It seems to me that 'asynchronous coding' could sum up the entirety of 'using threads' in a language like C# or Java. Is this the case?

No. There is one class of work that does not fit well with asynchrony: CPU-bound algorithms. In this case, your "work" has actual CPU code that it must run on an actual CPU. If you're doing something like that, you need real threads. In this case, you'd want parallelism rather than asynchrony. Parallelism is slowly coming to JavaScript, but they're starting at a very low level and it will be quite some time before high-level parallelism is a viable option.

Side note: C# code can choose to run asynchronous code all on one thread. In fact, this is the default environment for client-side apps (UI apps on desktop/mobile). The multi-threaded asynchronous environment is generally only used on the server, e.g., ASP.NET.

My understanding of threads is code that executes on 2 separate processors at the same time

It can. This depends on the cores in the machine and what else the machine is doing. .NET provides high-level parallelism abstractions for splitting up your work into chunks and distributing those among threads, where the threads run on cores, and doing all of this in a highly intelligent and adaptive manner. JavaScript currently has no parallelism support like this.

It seems to me that point 2/3 are effectively handling asynchronous code in exactly the same logical manner that I would have with JavaScript.

Yes, except for the fact that JavaScript asynchronous code cannot be CPU-bound. E.g., you could use parallelism on .NET to calculate a fractal; you can't do this using only async/await (regardless of language).

From my inexperienced perspective with C#, it seems that asynchronous coding in JavaScript has many similarities to multi-threaded coding in C#.

From a high-level perspective, yes: they're both forms of concurrency.

If you mean that async/await in JavaScript is similar to async/await in C#, then yes, they're practically the same thing. async/await are used to implement asynchrony in both languages.

Though with different use-cases... The one difference I can see is that code in JavaScript never executes simultaneously with other code, whereas in C# it might - is this where the idea of 'thread safety' comes from? i.e. a thread's state can't be altered by operations on another thread (I think)...

Yes, any time you have multi-threading, you need to ensure thread safety. So, any kind of parallel code in C# needs to ensure it is threadsafe. Asynchronous code in a multi-threaded environment can also run into thread safety issues, but that's more rare (most asynchronous code is serial, which can have no thread safety issues).

How do I run code after all threads have finished running?

Wrap the threading in a promise. You can check in the parent thread if there is a disconnect event, and if the amount of disconnects is equal to the number of threads, then you can resolve the promise.

Here is what I have

while (indexSize !== indexSizeLimit) {
let nextQueue = [];
const queueLength = queue.length;
const numberOfThreads = Math.min(numberOfCPUs, queueLength);
const threadAllocations = Array(numberOfThreads).fill(0);
let queuesAllocated = 0;
// queueChunks: [[{_id: ..., ...}], [...], ...]
const queueChunks = [];

function fillQueueChunks() {
loop: while (true) {
for (let i = 0; i < numberOfThreads; i++) {
threadAllocations[i] += 1;
queuesAllocated += 1;

if (queuesAllocated === queueLength) {
break loop;
};
};
};

let start = 0;

for (let threadAllocation of threadAllocations) {
const end = start + threadAllocation;

queueChunks.push(queue.slice(start, end));

start = end;
};
};

fillQueueChunks();

await new Promise(async function (resolve) {
if (cluster.isMaster) {
let threadsDone = 0;

for (let i = 0; i < numberOfThreads; i++) {
cluster.fork();
};

cluster.on("disconnect", function (_) {
threadsDone += 1;

if (threadsDone === numberOfThreads) {
resolve("Queue Processed");
};
});
} else {
const queueJob = queueChunks[cluster.id - 1];

await Promise.all(queueJob.map(function (queueItem) {
return new Promise(async function (resolve) {
const url = queueItem._id;
const webcode = await request(url);

if (webcode !== "Failure") {
const document = Document(url, webcode);
let hrefs = document.hrefs();
const hrefsQuery = Query(hrefs);

await document.save();

indexSize += 1;
hrefs = hrefsQuery.individualize();

const hrefIncidences = Promise.all(hrefs.map(function (href) {
return new Promise(async function (resolve) {
const incidences = await Site.countDocuments({
url: href
});

resolve(incidences);
});
}));

hrefs = hrefs.filter(function (_, i) {
return hrefIncidences[i] === 0;
}).map(function (href) {
return {
_id: href
};
});

await Queue.insertMany(hrefs);

nextQueue = nextQueue.concat(hrefs);
};

await Queue.deleteOne({
_id: url
});

resolve("Success");
});
}));

process.exit(0);
};
});

queue = nextQueue;
};


Related Topics



Leave a reply



Submit