This article was reproduced from: http://mp.weixin.qq.com/s?__biz=MzAxODI5ODMwOA==&mid=2666538919&idx=1&sn= 6013c451b5f14bf809aec77dd5df6cff&scene=21#wechat_redirect
On a "chat chat synchronous, asynchronous, blocking and non-blocking" has been popular explanation, to understand the synchronous, asynchronous, blocking and non-blocking important two conceptual points, have not seen, it is recommended to read this blog post to understand the two conceptual points. In cognition, a unified model is established. In this way, when we continue to read this article, we will not understand the deviation.
So what is the difference between blocking IO and non-blocking IO, before formally starting the Linux IO model, for example: Synchronous IO and asynchronous IO? The answers given by different people in different contexts are different. So first limit the context of this article.
1 Concept Description
Before interpreting, there are a few concepts to be explained:
User space and kernel space
Process switching
Blocking of processes
File descriptor
Cache IO
1.1 User space and kernel space
Now that the operating system is using virtual memory, the 32-bit operating system, its addressing space (virtual storage space) is 4G (2 of 32). The core of the operating system is the kernel, which is independent of the normal application, has access to protected memory space, and has all the permissions to access the underlying hardware device. In order to ensure that the user process can not directly manipulate the kernel (kernel), to ensure the security of the kernel, the operating system divides the virtual space into two parts, part of the kernel space, part of the user space. For the Linux operating system, the highest 1G bytes (from the virtual address 0xc0000000 to 0xFFFFFFFF) for the kernel to use, called the kernel space, and the lower 3G bytes (from the virtual address 0x00000000 to 0xBFFFFFFF) for each process to use, Called User space.
1.2 Process Switching
To control the execution of a process, the kernel must have the ability to suspend a process that is running on the CPU and resume execution of a previously suspended process. This behavior is called process switching. So it can be said that any process that runs under the support of the operating system kernel is closely related to the kernel.
The process of moving from one process to another runs through the following changes:
Save the processor context, including program counters and other registers.
Update PCB information.
The PCB of the process is moved into the appropriate queue, such as ready, in an event blocking queue.
Select another process to execute and update its PCB.
Update the data structure of memory management.
Restore the processing machine context.
Note: In short, it is very resource-intensive, specific reference to this article: process switching.
1.3 Blocking of the process
The executing process, because some expected events did not occur, such as requesting system resources failed, waiting for the completion of an operation, new data has not arrived or no new work to do, etc., the system automatically executes the blocking primitive (block), making itself from the running state into a blocking state. It can be seen that the blocking of a process is an active behavior of the process itself, and therefore it is possible to turn it into a blocking state only if the process is in a running state (acquiring the CPU). When a process goes into a blocking state, it does not consume CPU resources.
1.4 File Descriptor FD
File descriptor, a term in computer science, is an abstraction that describes a reference to a file.
The file descriptor is formally a non-negative integer. In fact, it is an index value that points to the record table in which the kernel opens a file for each process maintained by the process. When a program opens an existing file or creates a new file, the kernel returns a file descriptor to the process. In programming, some of the underlying programming often revolves around file descriptors. However, the concept of file descriptors is often applied only to operating systems such as UNIX and Linux.
1.5 Cache IO
Cache Io is also known as standard IO, and most file system default IO operations are cache io. In the Linux cache IO mechanism, the operating system caches the IO data in the file system's page cache, which means that the data is copied into the buffer of the operating system kernel before it is copied from the operating system kernel buffer to the application's address space.
Disadvantages of Cache IO:
Data is required to perform multiple copies of data in the application address space and the kernel during transmission, and the CPU and memory overhead of these data copy operations is very large.
2 Linux IO model
The essence of network IO is the socket read, socket in Linux system is abstracted as stream, IO can be understood as the operation of convection. Just now, for an IO access (read example), the data is copied to the operating system kernel buffer before it is copied from the operating system kernel buffer to the application's address space. So, when a read operation occurs, it goes through two stages:
First stage: Waiting for data preparation (waiting for the.
Phase two: Copy the data from the kernel into the process (Copying the data from the kernel-the process).
For the socket stream,
The first step: usually involves waiting for a packet of data on the network to arrive and then being copied to a buffer in the kernel.
Step Two: Copy the data from the kernel buffer to the application process buffer.
Network applications need to deal with nothing more than two major types of problems, network IO, data calculation. Compared with the latter, the latency of network IO brings the performance bottleneck to the application more than the latter. The network IO model is roughly as follows:
Synchronization model (synchronous IO)
Blocking io (bloking io)
Non-blocking IO (non-blocking io)
Multiplexed io (multiplexing io)
Signal-driven IO (signal-driven io)
Asynchronous IO (Asynchronous IO)
Note: Since signal driven IO is not commonly used in practice, I only refer to the remaining four IO Model.
Before going into the various models of Linux IO, let's explore the simple matrix of the basic Linux IO model. As shown in the following:
Each IO model has its own usage pattern, which has its own advantages for a particular application. This section will briefly describe each of them. Common IO models are blocking, non-blocking, Io multiplexing, and asynchronous. Illustrate these four concepts in a vivid example. I went shopping with my girlfriend at the weekend, I was hungry at noon, we were ready to go to dinner. Weekend people, eat need to queue, my girlfriend and I have the following options.
2.1 Synchronous Blocking io (blocking IO)
2.1.1 Scenario Description
My girlfriend and I after the meal, do not know when to do a good job, had to sit in the restaurant and so on, until finished, and then left to eat. My girlfriend would like to go shopping with me, but I do not know when the meal can be done, and I have to and I together in the restaurant and so on, and can not go shopping, until after eating dinner before going shopping, in the middle of waiting for the cooking time wasted. This is typical of blocking.
2.1.2 Network Model
The synchronous blocking IO model is the most commonly used model and the simplest model. In Linux, all sockets are blocking by default. It conforms to the most common thinking logic of people. Blocking is the process of "being" rested, CPU processing other processes went.
In this IO model, the user-space application executes a system call (Recvform), which causes the application to block and do nothing until the data is ready, and the data is copied from the kernel to the user process, and the final process processes the data, waiting for the data to process the data in two stages, The entire process is blocked. Cannot process other network IO. The calling application is in a state where the CPU is no longer consumed and simply waits for a response, so it is very effective from a processing point of view. When you call the recv ()/recvfrom () function, the process of waiting for data and replicating data in the kernel, such as:
2.1.3 Process Description
When the user process calls recv ()/recvfrom () This system call, kernel begins the first phase of IO: Preparing the data (for network IO, many times the data has not arrived at the beginning.) For example, you have not received a full UDP packet. This time kernel will have to wait for enough data to arrive. This process needs to wait, which means that the data is copied into the buffer of the operating system kernel, which requires a process. On this side of the user process, the entire process is blocked (of course, by the process's own choice of blocking). Second stage: When kernel waits until the data is ready, it copies the data from the kernel to the user's memory, and then kernel returns the result, and the user process removes the block state and re-runs it.
Therefore, the blocking IO is characterized by block in both phases of IO execution.
Advantages:
Be able to return data in time without delay;
This is a hassle for the kernel developers;
Disadvantages:
For the user is waiting to pay the cost of performance;
2.2 Synchronous non-blocking IO (nonblocking io)
2.2.1 Scenario Description
My girlfriend is not willing to wait in vain, and want to go shopping malls, but also worried about the food good. So we stroll for a while, come back to ask the waiter meal good no, to go back and forth several times, the meal has not eaten is almost exhausted. This is non-blocking. Need constant questioning, are you ready?
2.2.2 Network Model
Synchronous non-blocking is a polling (polling) method that "glances at the progress bar every once in a while." In this model, the device is opened in a non-blocking form. This means that the IO operation is not completed immediately, and the read operation may return an error code stating that the command is not immediately satisfied (Eagain or Ewouldblock).
In the network IO, the non-blocking IO will also make recvform system calls, check whether the data is ready, and blocking IO is not the same, "non-blocking the large block of time is divided into more than n small blocking, so the process has a chance to ' be ' CPU patronage."
That is, after a non-blocking recvform system call, the process is not blocked, the kernel is returned to the process immediately, and if the data is not ready, an error is returned. After the process returns, it can do something else before initiating the recvform system call. Repeat the above process and iterate through the recvform system calls. This process is often called polling. Poll the kernel data until the data is ready, and then copy the data to the process for data processing. It is important to note that the process of copying data is still a blocking state.
Under Linux, you can make it non-blocking by setting the socket. When you perform a read operation on a non-blocking socket, the process:
2.2.3 Process Description
When the user process issues a read operation, if the data in the kernel is not yet ready, it does not block the user process, but returns an error immediately. From the user process point of view, it initiates a read operation and does not need to wait, but immediately gets a result. When the user process determines that the result is an error, it knows that the data is not ready, so it can send the read operation again. Once the data in the kernel is ready and again receives the system call of the user process, it immediately copies the data to the user's memory and then returns.
Therefore, nonblocking IO is characterized by the user process needs to constantly proactively ask kernel data well no.
Synchronous non-blocking mode compared to synchronous blocking mode:
Pros: Ability to do other work while waiting for the task to complete (including submitting other tasks, i.e. "backstage" can have multiple tasks at the same time).
Disadvantage: The response delay for task completion is increased because each time a read operation is polled, the task may be completed at any time between polling two times. This can result in a decrease in overall data throughput.
2.3 io multiplexing (IO multiplexing)
2.3.1 Scenario Description
Similar to the second scenario, the restaurant installed an electronic screen to display the status of the order, so that my girlfriend and I go shopping for a while, come back without having to ask the waiter, directly to see the electronic screen on it. So that everyone's meal is good, all directly look at the electronic screen can be, this is the typical IO multiplexing.
2.3.2 Network Model
Because synchronous non-blocking mode requires constant active polling, polling takes up a large part of the process, polling consumes a lot of CPU time, and "backstage" may have multiple tasks at the same time, people think of the loop to query the completion status of multiple tasks, as long as any one task is completed, to deal with it. If polling is not the user state of the process, it is good to have someone help. So this is called "IO multiplexing". Unix/linux The Select, poll, Epoll is to do this (epoll than poll, select high efficiency, do the same thing).
IO multiplexing has two special system calls to select, poll, and Epoll functions. Select calls are kernel-level, and select polls are the difference between non-blocking polling-the former can wait for multiple sockets to be able to listen to multiple IO ports at the same time, and when any one of the sockets is ready, the data can be returned for readability. The process then makes the recvform system call, copying the data from the kernel to the user process, of course, the process is blocked. After a select or poll call, the process is blocked, unlike the blocking IO blocking, where the select does not wait until the socket data is fully processed, but a portion of the data is invoked to process the user processes. How do you know if some of the data arrives? The monitoring is given to the kernel and the kernel is responsible for the processing of data arrival. It can also be understood as "non-blocking".
The I/O multiplexing model uses the Select, poll, Epoll functions, which also block the process, but unlike blocking I/O, these two functions can block multiple I/O operations at the same time. I/O functions can be detected at the same time for multiple read operations and multiple write operations, until there is data readable or writable (note that not all data is readable or writable) before actually invoking the I/O operation function.
For multiplexing, that is, polling multiple sockets. Since multiplexing can handle multiple IO, it brings new problems, the order of multiple IO becomes uncertain, and of course it can be used for different numbers. The specific process, as shown in:
2.3.3 Process Description
Io Multiplexing is what we call Select,poll,epoll, and in some places this IO mode is the event driven IO. The benefit of Select/epoll is that a single process can simultaneously handle multiple network connections of IO. The basic principle of the select,poll,epoll is that the function will constantly poll all sockets that are responsible, and when a socket has data arrives, notifies the user of the process.
When the user process invokes select, the entire process is blocked, and at the same time, kernel "monitors" all select-responsible sockets, and when the data in any one socket is ready, select returns. This time the user process then invokes the read operation, copying the data from the kernel to the user process.
Multiplexing is characterized by a mechanism in which a process can simultaneously wait for an IO file descriptor, the kernel monitors these file descriptors (socket descriptors), any one of which goes into the read-ready state, select, the Poll,epoll function can be returned. For the way of monitoring, can be divided into Select, poll, Epoll three ways.
The graph above and blocking IO are not very different, in fact, worse. Because two system calls (select and Recvfrom) are required, blocking IO only invokes one system call (Recvfrom). However, the advantage of using select is that it can handle multiple connection at the same time.
Therefore, if the number of connections processed is not high, Web server using Select/epoll does not necessarily perform better than the Web server using multi-threading + blocking IO, and may be more delayed. (The advantage of Select/epoll is not that a single connection can be processed faster, but that it can handle more connections.) )
In the IO multiplexing model, the actual, for each socket, is generally set to become non-blocking, but, as shown, the entire user's process is actually always block. Only the process is the block of the Select function, not the socket IO. So IO multiplexing is blocking over system calls such as Select,epoll, without blocking on real I/O system calls such as Recvfrom.
Understanding the previous three IO modes, when the user process makes system calls, they wait for the data to arrive, the way of processing different, direct waiting, polling, select or poll polling, two stages of the process:
The first stage has some blocking, some do not block, some can block and can not block.
The second stage is blocked.
From the whole IO process, they are executed sequentially, so they can be classified as synchronous models (asynchronous). is the process actively waiting and checking the state to the kernel. "This sentence is very important!!! 】
Highly concurrent programs generally use synchronous non-blocking rather than multithreading + synchronous blocking. To understand this, the first thing to do is to pull the difference between concurrency and parallelism. For example, to a department to do business needs to go to several windows, the number of Office Hall is the number of concurrent, and the number of Windows is the degree of parallelism. That is, concurrency is the number of simultaneous tasks (such as HTTP requests for simultaneous service), while the number of parallel is the amount of physical resources (such as CPU cores) that can work concurrently. By reasonably dispatching different stages of a task, the number of concurrent numbers can be far greater than the degree of parallelism, which is the mystery of just a few CPUs that can support tens of thousands of concurrent requests. In this high-concurrency scenario, it is very expensive to create a process or thread for each task (user request). Synchronous nonblocking mode can throw multiple IO requests into the background, which can serve a large number of concurrent IO requests in a single process.
Note: IO Multiplexing is a synchronous-blocking or asynchronous-blocking model, which is analyzed here:
It is still not clear here, it is strongly recommended that in scrutiny "chat synchronization, asynchronous, blocking and non-blocking" in the fundamental difference between synchronous and asynchronous, synchronization is the need to actively wait for message notification, and asynchronous is to passively receive message notification, through callback, notification, state and other ways to passively get the message. Io multiplexing when blocking to the Select phase, the user process is actively waiting for and calling the Select function to get a data-ready status message, and its process state is blocked. Therefore, the IO multiplexing is classified as synchronous blocking mode.
2.4 Signal-driven IO (signal-driven io)
Signal-driven I/O: First we allow the socket to signal-drive IO and install a signal processing function, and the process continues to run without blocking. When the data is ready, the process receives a sigio signal that can be called by the I/O operation function in the signal processing function to process the data. The process is as follows:
2.5 Asynchronous non-blocking IO (asynchronous IO)
2.5.1 Scenario Description
Girlfriend do not want to shop, and restaurant too noisy, go home and have a good rest. So we call takeout, make a phone call to order, and then my girlfriend and I can have a good rest at home, the food is good delivery staff to send to the home. This is the typical asynchronous, just need to make a phone call, and then can do their own things, the meal is ready to send.
2.5.2 Network Model
Asynchronous IO is not sequential execution, relative to synchronous IO. After a user process makes a aio_read system call, the kernel data is returned directly to the user process, regardless of whether it is ready, and then the user-state process can do something else. When the socket data is ready, the kernel copies the data directly to the process and sends notifications from the kernel to the process. IO Two stages, the process is non-blocking.
Linux provides an AIO library function for asynchronous implementations, but with little use. There are many open-source asynchronous IO libraries, such as Libevent, Libev, LIBUV, and so on. The asynchronous process looks like this:
2.5.3 Process Description
After the user process initiates the aio_read operation, you can begin to do other things immediately. On the other hand, from the perspective of kernel, when it receives a asynchronous read, first it returns immediately, so no block is generated for the user process. Then, kernel waits for the data to be ready and then copies the data to the user's memory, and when all this is done, kernel sends a signal to the user process or executes a thread-based callback function to complete the IO process, telling it that the read operation is complete.
In Linux, the way to notify is "signal":
If the process is busy doing something else (for example, calculating the product of two matrices), break it up and invoke the pre-registered signal handler, which can determine when and how to handle the asynchronous task. Since the signal processing function is suddenly broken in, as with the interrupt handler, there are a lot of things that cannot be done, so on the safe side, it is usually to "register" the event and put it in the queue, then return to what the process was doing.
If this process is busy doing other things in the kernel state, such as to read and write the disk in a synchronous blocking way, then we have to hang up the notice, wait until the kernel state is busy, and will return to the user state, and then trigger the signal notification.
If the process is now suspended, such as nothing to do sleep, then wake up the process, the next time the CPU is idle, it will be dispatched to this process, triggering signal notification.
The asynchronous API is lightweight and hard to do, mainly for the implementation of the API. Asynchronous IO (AIO) support for Linux was introduced by 2.6.22, and many system calls do not support asynchronous IO. The asynchronous IO of Linux was originally designed for the database, so read and write operations through asynchronous IO are not cached or buffered, which makes it impossible to exploit the caching and buffering mechanisms of the operating system.
Many people think of Linux's o_nonblock as asynchronous, but in fact this is a synchronous non-blocking approach that was previously spoken. It should be noted that although the IO API on Linux is slightly coarser, each programming framework has a encapsulated asynchronous IO implementation. Operating system less work, more freedom to the user, it is UNIX design philosophy, but also the Linux programming framework for a flourishing of the reason.
From the classification of the preceding IO model, we can see the motive of AIO:
The synchronous blocking model needs to block the application at the start of the IO operation. This means that processing and IO operations cannot overlap at the same time.
Synchronous nonblocking models allow processing and IO operations to overlap, but this requires the application to check the status of the IO operation based on the recurring rules.
This leaves asynchronous nonblocking io, which allows processing and IO operations to overlap, including notification of completion of IO operations.
In addition to blocking, the function provided by the Select function (asynchronous blocking IO) is similar to AIO in IO multiplexing. However, it is blocking the notification event rather than blocking the IO call.
2.6 about asynchronous blocking
Sometimes our API only provides asynchronous notification methods, such as in node. JS, but the business logic needs to do one thing after another, such as initializing the database connection to start accepting HTTP requests from the user. Such business logic requires the caller to work in a blocking manner.
In order to simulate the effect of "sequential execution" in an asynchronous environment, it is necessary to convert the synchronous code into an asynchronous form, called the CPS (continuation passing Style) transformation. The Continuation.js Library of Byvoid is a CPS transformation tool. The user simply writes the code in a synchronous way that is more common to the human common sense, and the CPS transforms it into a layered, nested asynchronous callback form.
Another reason to use blocking methods is to reduce response latency. If the non-blocking way, a task A is submitted to the background, start to do another thing B, but B has not finished, A is finished, this time to let A's completion of the event is processed as soon as possible (for example, A is an emergency), or discard to do half of B, or save the middle State of b and switch back to A, Time (either from disk to memory or from memory to cache), which is bound to slow the response of a. Therefore, in real-time systems or latency-sensitive transactions, blocking is sometimes better than non-blocking mode.
2.7 of five IO models
Talk about five IO models in Linux