In a heated debate over technicalities on the internet, you may have heard the argument "Yeah, that may be concurrent but not parallel computing." You're wondering what do they mean anyway? What's the difference? Most importantly, should I care?

As it turns out, Node.js can be categorized into one of these. On the general level, though, as long as you keep in mind that the CPU is pretty much always keeping several balls in the air, you're all good.

More work than there are resources

Let's assume that there is more work to be done than there are resources for doing them. That there are multiple threads or sequences of operations to step through. With only one thread or operation sequence, there isn't much to discuss in terms of concurrency or parallelism.

Concurrent

Concurrent operation means that two computations can both make progress and advance regardless of the other. If there are two threads, for example, then both make progress independently. The second computation doesn't need to wait for the first one to complete before it can be advanced.

Figure 1. Pre-emptive multithreading is one way to achieve concurrency.

If computation is said to be concurrent, then it doesn't necessarily dictate how the concurrency is achieved under the hood. In single-core setup, it is possible that the computations take turns in execution. The CPU might run few instructions from the other thread, then suspend it and switch over to the second and run a few steps from it and so on. This is also called pre-emptive multithreading. It may also be possible that there are more cores available that can be used to run both at the same time. This, in fact, is parallel computation, as we'll see next.

Parallel

Figure 2. Parallel computation advances simultaneously.

Parallel operation means that two computations are literally running at the same time. At one point in time, both computations advance. There is no taking turns; they advance at the same time. Naturally this is not possible with single-core CPU, but multiple-core architecture is required instead.

It can be said that if computation is parallel, it is also concurrent - since parallel computation also fulfills the definition of concurrent computation.

Node.js perspective

At a high level, Node.js falls into the category of concurrent computation. This is a direct result of the single-threaded event loop being the backbone of a Node.js application. The event-loop repeatedly takes an event and then sequentially executes all listeners interested in that event. The event loop never runs two pieces of JavaScript in parallel.

As long as the event handlers are small and frequently wait for yet more events themselves, all computations (for example fulfilling and serving a HTTP request) can advance one small step at a time - concurrently. This is beneficial in web applications where the majority of the time is spent waiting for I/O to complete. It allows a single Node.js process to handle huge amounts of requests.

While it's not possible to run two pieces of JavaScript at the same time that would have access to shared JS objects, there are few ways you can run isolated JavaScript computations in parallel. To achieve this, you can launch multiple node processes or child processes using the cluster module. And, starting from Node v10, you can launch a given piece of JavaScript code in a worker thread and synchronize by passing copies of JS objects. A good mental model for tackling this braintwister, is to think that you're effectively launching multiple event-loops.

Related articles