This is the 28th day of my participation in the August Text Challenge.More challenges in August
The previous article introduced why we need asynchronous I/O in terms of user experience and resource allocation. This article focuses on asynchronous I/O support at the operating system level.
Asynchronous I/O is most widely used in NodeJS, but it is not the original nodeJS. Let’s take a look at the operating system support for asynchronous I/O.
Asynchronous AND non-blocking I/O
The concepts of asynchrony and non-blocking may sound similar and both can achieve the same effect as we do with parallel I/O, but in reality they are not the same thing for an operating system.
The operating system kernel has only two ways to handle I/O: blocking and non-blocking.
When blocking I/O is invoked, the application waits for the I/O to complete, that is, for the operating system kernel to complete all its work, before returning the result. As a result, the CPU waits for I/O and cannot be fully utilized, as shown in the following figure:
To improve performance, the kernel provides a non-blocking I/O that returns immediately after the call, as shown below:
After the non-blocking I/O is returned, the CPU time slice can be used to do other things, which can improve performance compared to blocking I/O.
But because non-blocking I/O immediately returns not the final result, but the current state of a call, the application needs to iterate, or poll the call I/O, to see if the operation is complete. Polling also requires the CPU to process the result of the operation, and it has its drawbacks for the application to constantly send I/O requests.
Ideal non-blocking asynchronous I/O
The asynchronous I/O we expect is that the application initiates a non-blocking call, no need to get the result through traversal or polling, and can directly process the following tasks. After the I/O is completed, it can be directly returned to the application through signal or callback, as shown in the figure below:
The approach described above, called AIO, exists on Linux, but it exists only on Linux and does not take advantage of the system cache.
Realistic asynchronous I/O
We discussed the single-threaded case earlier, and if you use multiple threads, you can simulate the ideal case. Some threads can be blocked or non-blocked + polling to carry out I/O operations, and one thread can carry out computational processing and transfer I/O data through communication between threads, as shown in the following figure:
* Asynchronous I/O is implemented in different ways on NIx and Windows, namely custom thread pools and IOCP, respectively. Nodejs’ Libuv layer smoothen the differences between different operating systems, ensuring that nodeJS ‘upper and operating system implementations are independent of each other.
We mentioned earlier that NodeJS is single-threaded, but it is only single-threaded at the JavaScript execution level. In fact, on both * NIx and Windows, there are separate thread pools for internal I/O tasks.
This article is a summary of the chapter on asynchronous I/O in NodeJS