The Difference Between I/O Tasks and CPU-Intensive Tasks

The Difference Between I/O Tasks and CPU-Intensive Tasks

The Issue

As a Node.js developer, have you ever heard about the strength of Node.js in processing I/O tasks and asynchronous operations, and that it may not be the best choice for CPU-intensive applications? So, what are I/O tasks and why is Node.js strong in I/O? Is it indeed true that Node.js is not good for heavy computational tasks? In today's article, I will take the time to discuss these issues.

What are I/O Tasks?

I/O (Input/Output) refers to the interaction of a computer or computer program with the system's disk and network. Examples of I/O activities include reading/writing data from/to disk, performing HTTP requests, and interacting with databases. These activities are slower compared to accessing RAM or performing computations on the CPU.

How V8 Executes JavaScript Code

We know that Node.js utilizes Chrome's V8 engine to execute JavaScript code, but even with the power of V8, it falls behind with I/O tasks as they do not solely depend on the CPU's processing speed but on disk read/write speed, network speed, etc. If I/O was handled within V8, it would lead to severe bottlenecks due to the significant amount of time it takes. This is why Node.js had to find a solution to leverage the power of V8 while still dealing with I/O.

Node.js's solution is to use libuv for asynchronous I/O operations. Libuv is a cross-platform C library that provides support for asynchronous I/O operations based on an event loop.

V8 + libuv in Node.js

The main thread pushes I/O tasks to libuv, and the results are returned to the main thread through the event loop. This creates an infinite loop where the main thread is not blocked by I/O anymore.

In Node.js, there is a concept of workers that are responsible for transferring I/O requests from the main thread to libuv and waiting for responses. During this time, they do not perform any other tasks and can be descheduled by the operating system to allow another worker to send requests. Hence, I/O tasks submitted by workers in advance will still be processed even when the event loop is not running.

The operating system has optimized the file management tools and databases for simultaneous handling of multiple pending requests. For instance, it rearranges priority order when there are concurrent read/write requests to a file.

When running a Node.js application, you will have a dedicated thread pool to handle I/O requests. This thread pool is created by libuv. Its default size is 4, but it can be increased up to a maximum of 128 through the UV_THREADPOOL_SIZE environment variable.

libuv's Structure

CPU-Intensive Tasks

These are tasks that require a significant amount of CPU computing power. They can include complex operations such as encoding/decoding, image processing, video processing, etc. Workers can also handle these complex computational requests, schedule and process them outside the main thread. However, they are only processed when a worker is scheduled on one of the CPU cores. For example, if your CPU has 4 cores and you create 5 workers, one of them will not participate in the processing, while still consuming resources (memory and scheduling overhead), leading to resource wastage.

Worker Thread Model

To understand how Node.js handles heavy computational tasks with Worker Threads, I recommend you read the article What are Worker Threads? Do you know when to use Worker Threads in Node.js?.

It can be observed that if the main thread handles I/O tasks with libuv, it prevents severe bottlenecks. Meanwhile, CPU-intensive tasks will take up processing time. The solution is to create child processes or worker threads, but these solutions also depend on the hardware's capabilities.

Conclusion

With Node.js's architectural design, it is designed to leverage the power of V8 while still addressing I/O. Hence, Node.js is suitable for I/O-centric problems. However, it is not true that Node.js cannot handle heavy computational tasks. By creating child processes or worker threads on multi-core CPUs, these tasks can be processed without blocking the main thread.

or
* The summary newsletter is sent every 1-2 weeks, cancel anytime.
Author

Hello, my name is Hoai - a developer who tells stories through writing ✍️ and creating products 🚀. With many years of programming experience, I have contributed to various products that bring value to users at my workplace as well as to myself. My hobbies include reading, writing, and researching... I created this blog with the mission of delivering quality articles to the readers of 2coffee.dev.Follow me through these channels LinkedIn, Facebook, Instagram, Telegram.

Did you find this article helpful?
NoYes

Comments (1)

Avatar
Đăng Khoa2 years ago
Hoá ra v8 để chạy mã js và nó một luồng đúng ko ạ
Reply
Avatar
Thành Đỗ2 years ago
Đúng rồi bác