Home  >  Article  >  Web Front-end  >  An in-depth analysis of multi-threading and multi-processing in Node.js

An in-depth analysis of multi-threading and multi-processing in Node.js

青灯夜游
青灯夜游forward
2020-08-31 09:55:192619browse

An in-depth analysis of multi-threading and multi-processing in Node.js

Node.js is a free cross-platform JavaScript runtime environment. Although it is single-threaded in nature, it can use multiple threads in the background to Execute asynchronous code.

Due to the non-blocking nature of Node.js, different threads execute different callbacks, which are first delegated to the event loop. The Node.js runtime handles all of this. [Video tutorial recommendation: node js tutorial]

Why use NodeJS?

JavaScript was originally built as a single-threaded programming language that only runs in a web browser. This means that within a process, only one set of instructions can be executed at a given time.

Move to the next code block only after execution of the current code block is complete. However, the single-threaded nature of JavaScript makes implementation easy.

Initially, JavaScript was only used to add a small amount of interactivity to the website. So there is no need for multi-threading. But times have changed, users have become more demanding, and JavaScript has become “the most popular programming language on the Web.”

Multiple threads are becoming common nowadays. Since JavaScript is a single-threaded language, multi-threading cannot be implemented in it. Fortunately, in this case, there is a great solution: Node.js.

Node.js frameworks are not lacking, thanks to the general popularity of JavaScript runtime environments (especially JavaScript). Before continuing with this article, let us understand some important points about Node.js:

  1. You can use the send function to pass messages from child processes to other child processes and the main process
  2. Support Fork multiple processes
  3. No state is shared between the main process and the child process

Why fork the process?

In two cases we need to fork a process:

  1. Increase speed by delegating tasks to other processes
  2. For freeing memory and unloading a single Process

can send data to the child process and can also send it back.

The Node.js way

Node.js uses two types of threads:

  1. The main thread handles the
  2. work via the event loop There are many worker threads in the pool

The event loop is responsible for getting callbacks or functions and registering them for future execution. It runs in the same thread as the correct JavaScript code. Once a JavaScript operation blocks the thread, the event loop is also blocked.

The work pool is an execution model responsible for generating and processing different threads. It executes the task synchronously, then returns the result to the event loop, and finally the event loop provides the result to the callback.

In summary, the work pool is responsible for asynchronous I/O operations, that is, interaction with the system disk and network. Modules like fs and crypto are the main modules that use worker pools.

Since the worker pool is implemented in the libuv library, Node.js has a slight delay in internal communication between JS and C. But it's almost imperceptible.

Everything is fine until we encounter the requirement to perform complex operations synchronously. Any function that takes a large amount of time to execute will cause the main thread to block.

If a program has multiple CPU-intensive functions, it will cause a significant decrease in server throughput. In the worst case, the server will become unresponsive and unable to delegate tasks to the worker pool.

Domains such as AI, big data, and machine learning cannot benefit from Node.js because these operations block the main thread and make the server unresponsive. But that changes with the arrival of Node.js v10.5.0, which adds support for multi-threading.

Challenges of Concurrency and CPU-bound Tasks

Establishing concurrency in JavaScript can be difficult. Allowing multiple threads to access the same memory can lead to race conditions that not only make the failure difficult to reproduce, but also difficult to resolve.

Node.js was originally implemented as a server-side platform based on asynchronous I/O. This makes a lot of things easier by simply eliminating the need for threads. Yes, Node.js programs are single-threaded, but not in the typical way.

We can run in parallel in Node.js, but there is no need to create threads. The operating system and virtual machine work together to use I/O in parallel, and then when data needs to be sent back to the JavaScript code, the JS code runs in a single thread.

Everything except the JS code runs in parallel in Node.js. Unlike asynchronous blocks, synchronous blocks in JS are always executed once at a time. Waiting for I/O events to occur in JS takes much more time than executing code.

Node.js programs only call the required functions or callbacks without blocking the execution of other code. Initially neither JavaScript nor Node.js was intended to handle CPU-intensive or CPU-bound tasks.

When code is minimal, execution will be agile. But the greater the amount of calculation, the slower the execution speed.

If you still try to complete CPU-intensive tasks in JS and Node, it will freeze the UI in the browser and queue all I/O events. Still, we've come a long way. Now there is the worker_threads module.

The worker_threads module makes multithreading easy

Node.js v10.5.0 was released in June 2018, introducing the worker_threads module. It helps achieve concurrency in popular JavaScript runtime environments. This module allows the creation of fully functional multi-threaded Node.js applications.

Technically speaking, a worker thread is some code generated in a separate thread. To start using worker threads, you need to import the worker_threads module first. You then need to create an instance of the Worker class to create a worker thread.

When creating an instance of the Worker class, there are two parameters:

  1. The first parameter provides the file path with the extension .js or .mjs, which contains the code for the worker thread ,
  2. The second parameter provides an object containing the workerData property, which contains the data that will be accessed when the worker thread starts execution

The secondary thread is able to schedule multiple message events. Therefore, callback methods take precedence over returning promises.

Communication between worker threads is event-based, that is, the listener is set to be called immediately after the worker thread sends the event. The 4 most common events are:

worker.on('error', (error) => {});
  1. Emitted when there is an uncaught exception in the worker thread. Next the worker thread terminates and the error is available as the first argument in the callback.
worker.on('exit', (exitCode) => {})
  1. Emitted when the secondary thread exits. If process.exit() is called in a worker thread, the exitCode will be provided to the callback. Code 1 if worker.terminate() terminates the worker thread.
worker.on('message', (data) => {});
  1. Emitted when the worker thread sends data to the parent thread.
worker.on('online', () => {});
  1. Emitted when the worker thread stops parsing JS code and starts executing. Although not commonly used, the online event may provide more information in certain situations.

Ways of using worker threads

There are two ways to use worker threads:

  • Method 1 – Involves generating work Thread that executes its code and sends the results to the parent thread. This method requires creating a new worker thread from scratch each time for a new task.
  • Method 2 – Involves spawning a worker thread and setting up listeners for message events. Each time the message is triggered, the worker thread executes the code and sends the results back to the parent thread. The worker thread is kept alive for future use.

Method 2 is also known as worker pool. This is because the method involves creating a pool of workers, letting them wait, and dispatching message events to perform tasks when needed.

Since creating a worker thread from scratch requires creating a virtual machine and parsing and executing code, the official Node.js documentation recommends method 2. Additionally, Method 2 is more practical and more effective than Method 1.

Important properties available in the worker_threads module

  • isMainThread – This property is true when not operating within a worker thread. If desired, you can include a simple if statement at the beginning of the worker file. This ensures it only runs as a worker thread.
  • parentPort – An instance of MessagePort used to communicate with the parent thread.
  • threadId – Unique identifier assigned to the worker thread.
  • workerData – Data contained in the constructor of the worker thread.

Multiple processes in Node.js

In order for Node.js to take advantage of the capabilities of a multi-core system, some processes can be used. The popular JavaScript runtime environment has a module called cluster that provides support for multiple processes.

Use the cluster module to generate multiple child processes, and these child processes can share a common port. Systems using NodeJS can handle larger workloads when child processes are put into use.

Node.js on the backend

The Internet has become the platform of choice for millions of companies around the world. Therefore, in order for a business to reach its maximum potential, and stand out in the process, it is necessary to have a strong online presence.

It all starts with a powerful and intuitive website. To create a flawless website, it is important to choose the best front-end and back-end technologies. Although single-threaded in nature, Node.js is the first choice for developing backend web services.

Despite the plethora of backend multi-threading options, big-name companies still prefer Node.js. This is because Node.js provides workarounds for using multithreading in JavaScript, which is already "the most popular programming language on the web."

Summary

The worker_threads module provides an easy way to implement multi-threading in Node.js programs. By delegating heavy calculations to worker threads, you can significantly increase your server's throughput.

With support for multi-threading, Node.js will continue to attract an increasing number of developers, engineers and other professionals from compute-intensive fields such as AI, big data and machine learning.

English original address: https://flatlogic.com/blog/multi-threading-and-multiple-process-in-node-js/

To ensure readability Sex, this article adopts free translation rather than literal translation.

For more programming-related knowledge, please visit: Programming Teaching! !

The above is the detailed content of An in-depth analysis of multi-threading and multi-processing in Node.js. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:segmentfault.com. If there is any infringement, please contact admin@php.cn delete