How JavaScript works: parallelism vs concurrency in JavaScript, what’s the difference?

Ukpai Ugochi
SessionStack Blog
Published in
9 min readJun 13, 2022

This is post # 65 of the series, dedicated to exploring JavaScript and its building components. In the process of identifying and describing the core elements, we also share some rules of thumb we use when building SessionStack, a JavaScript tool for developers to identify, visualize, and reproduce web app bugs through pixel-perfect session replay.

Multiple parts of a program can be executed at the same time. And these parts are called threads while the executed program is called a process. A thread is a basic unit of a process. This architecture allows a program to run even if some threads are blocked. When a thread is blocked, it is waiting to acquire resources.

The architecture where multiple threads are running concurrently is called multithreading. And this means that two or more tasks are progressing at the same time. Multiprocessing consists of more than two processors where multiple processes run simultaneously. Multiprocessing implements parallelism. Multiprocessing allocates separate memory and resources for each program — or process. But multithreading shares the same memory and resources for threads belonging to the same process.

This article will explore threads, process, parallelism, and concurrency, their characteristics, differences, and their use in JavaScript.

What are Threads and Processes

A process is a set of program codes that has been loaded into the computer memory for execution by the Central Processing Unit (CPU). It is an instance of a program that is running or active. Sometimes, people use a process and a program interchangeably. However, they are not the same. A process is different from a program because a program can only become a process when it has been loaded into the computer memory. Therefore, we can say that a process is an instance of an executing program. It is an active entity that is created during program execution. A process exists for a short time and gets terminated after the task completion. Now, what is a thread? or what are threads?

A thread in computer programming is a set of instructions designed to be executed by the CPU without dependency on the parent process. It is a lightweight process that executes code sequence and all the data supporting structures. A process starts with at least one thread from which more threads are created. And threads are important because they help conserve the time and energy that goes into complex context switching. For instance, to serve multiple users, a parent process needs to create some child processes. And in the case of an operating system with multiple CPUs, the child processes and parent process are each assigned to a CPU. What happens in complex programs with many processes that need to communicate with each other? Operating systems need to switch between processes and include memory management units (MMU) that will prevent a process from overrunning another process. This switch takes time and because the processes need a way to communicate with each other, the server may end up switching from one process to another without doing any work. Most of the problems highlighted above are solved with the creation of threads.

A process can be broken down into threads. Since threads within the same process share the same memory spaces and they are not independent of themselves like in the case of processes, this means that they can communicate with each other without the need of creating pipes like processes. The advantage of this is that it takes less time for the CPU to switch among threads, therefore it is faster and consumes less energy. Threading allows quick response in executing programs as dividing a process into multiple threads allows faster execution of tasks. Some things make threads unique, these are called the thread states.

New Thread

This is the state of a thread when it’s newly created. This thread isn’t running yet and isn’t executing any code. For instance, developers can spawn new worker threads using the worker constructor:

Running State

The running state is the state where the thread is running and currently executing tasks. When the thread is in the running state, they execute tasks from programs. In JavaScript workers, developers can use eventListeners to monitor threads and get information from the executed tasks. For instance, from the code below, we can get message from our task using the message event.

Block/Waiting State

This state renders the thread temporarily inactive. This is unique to threads since they can communicate with each other. For instance, a thread is blocked when it is waiting to acquire resources. A thread can also be waiting if it’s waiting on another thread to complete a task.

Terminate State

The terminate state is the state when the thread exits. Threads can terminate in the following ways:

  1. Because it exits normally.
  2. Exits due to other factors. For instance, when it meets an exception or when the developer terminates it.

In JavaScript worker, threads terminate naturally when not in use, and they restart when they are next needed. However, developers can use the terminate() method to terminate the thread immediately.

In subsequent sections, we’ll get a better understanding of what multithreading and multiprocessing are.

What is Multithreading

In the last section, we saw that a process can have multiple threads — a concept called multithreading Multithreading is a technique of program execution where a process has multiple code segments and this technique is also referred to as concurrency. In multithreading, each thread runs concurrently with the other. Consequently, increasing the computing power of the system.

Multiple threads that belong to the same process tend to share the same memory and resources that the process has. The advantage of having multiple threads is that code execution does not require too much memory space as threads of the same process share the same memory space and other resources. Also, threads are lightweight therefore they only occupy low memory space. Threading makes access to memory states from another context easier and simplifies the creation of responsive user interfaces.

Threading is an ideal option for an application that requires faster input and output operations. Less time is needed to switch between threads within the shared memory. And this is why CPUs can easily switch between multiple threads while the threads seem to run simultaneously.

Compared to a process, a thread starts faster. And it is easier to switch between multiple threads. Multithreading implements concurrency. Here, the CPU executes different tasks at the same time by switching between tasks.

What is Multiprocessing

And this increases the computing speed of the system linearly. This linear increase is because every processor added to the system increases the speed of the power and memory of the system. Increasing the computing speed of a system allows users to run multiple processes at the same time, and this makes program execution faster.

When a system implements multiprocessing, it executes parallelism. And this is a technique that describes the process of making programs run faster by performing several tasks at the same time. Each CPU added to the system has its memory and can function independently. Some processors may remain idle if they have nothing to execute. Multiprocessing increases the reliability of the system as unused CPUs can act as breakups. It also allocates separate memory and resources to each process or program, compared to multithreading where each thread of the same process shares the same memory and resources.

Also, multiprocessing removes synchronization, child processes are mostly interruptible and can be terminated without affecting the parent process.

In addition, multiprocessing helps in executing programs quickly, and it also helps in processing a large volume of that at high speed. And multiprocessing can be divided into two major categories: symmetric and asymmetric multiprocessing.

Both multiprocessing and multithreading are useful in increasing the computing power of a system. However, both have some key differences. For example, multiprocessing requires more than one CPU to speed up a system, while multithreading requires a single process with multiple threads. Also, multiprocessing requires more time, unlike multithreading which is quick and requires fewer resources like sharing of memory space.

Multithreading and Multiprocessing in JavaScript

By default JavaScript runtime environment (Nodejs) is single-threaded, which means it can only execute one set of instructions at a time in a process. For older browsers, all tabs shared a single thread. However, this made the working of the browser slow. Consequently, each tab now has a separate thread, thereby increasing the responsiveness of web pages.

Although the browser could handle multiple threads, with each tab having one tab, these tabs could not handle multiple processes at once because they were single-threaded.

And this can result in greater issues especially if the main thread gets blocked by laborious processes that might cause UI events to become slow. To solve this problem in 2009, JavaScript introduced web workers.

Web workers allow JavaScript codes to be executed from within the web page. It runs on a background thread instead of the main thread. Web workers help in running more intensive processes like multitasking without blocking the main thread since web workers run on separate threads from the main thread. Thus different web pages can eventually have multiple threads. For instance, we can create multi-threads for our program by using web worker as shown below:

JavaScript developers can also implement multithreading using the worker_thread module in Node.js.

Multiprocessing in JavaScript is mostly executed in server-side technology, as it allows more than one Node instance to run concurrently. Remember we noted above that JavaScript is single-threaded because its runtime engine (Nodejs) has only one thread. However, you can have multiple Nodejs instances running at once to prevent your application from crashing even if one Nodejs instance crashes and also prevent the application slow down when one Nodejs instance becomes occupied with CPU-intensive tasks. You can implement multiprocessing in JavaScript by using Node’s cluster module.

An example of how this is done is shown below:

Characteristics of multithreading and multiprocessing

Multiprocessing

  1. Improves system reliability
  2. Increases performance by breaking a program into executable parallel tasks
  3. Classified according to memory organization
  4. Requires more memory spaces and resource allocation for executing more processes at once
  5. Executes multiple processes simultaneously
  6. Create separate address space for each process

Multithreading

  1. In multithreading, each task(threads) runs parallel to each other
  2. Threads make use of the same memory allocation
  3. Makes use of a single process with multiple code segments to improve computational power
  4. Quick to create and requires few resources
  5. Executes multiple threads at the same time

Conclusion

Understanding how a system executes programs is required to create better software that serves its purpose.

In this article, we looked at what a process is and how it helps increase the speed of a program’s execution. I explained some of the characteristics of a process and threads. We also explored the concepts of multiprocessing and multithreading, with their differences.

I also talked about threading and processing in JavaScript. And how JavaScript can allow multithreading and multiprocessing and its usefulness. If you want to explore more about web workers, this article is a great fit. One great takeaway is that a system implementing multiprocessing executes tasks in parallel. And systems implementing multithreading execute tasks concurrently.

Both multithreading and multiprocessing are great for performance but even if you feel like the proper decisions have been made, it’s always necessary to verify that this is indeed true and your users have a great experience with your product.

A solution like SessionStack allows us to replay customer journeys as videos, showing us how our customers experience our product. We can quickly determine whether our product is performing according to their expectations or not. In case we see that something is wrong, we can explore all of the technical details from the user’s browser such as the network, debug information, and everything about their environment so that we can easily understand the problem and resolve it. We can co-browse with users, segment them based on their behavior, analyze user journeys, and unlock new growth opportunities for our applications.

There is a free trial if you’d like to give SessionStack a try.

SessionStack replaying a session

Interested in more about JavaScript? Check out all “How JavaScript works” publications here.

--

--