Concurrent programming: IO multiplexing.

An IO model:

  Stevens compared a total of five IO Models in the article:

    * blocking IO #blocking model 
    * nonblocking IO # non-blocking 
    * IO multiplexing # multiplexing 
    * signal driven IO #signal driven * asynchronous 
    IO #asynchronous by signal 
    driven IO (signal driven IO) is not commonly used in practice, so the main Introduce the remaining four IO Models.

    Let's talk about the objects and steps involved when IO occurs. For a network IO (here we take read as an example), it will involve two system objects, one is the process (or thread) that calls this IO, and the other is the system kernel (kernel). When a read operation occurs, the operation goes through two phases:

#1) Waiting for the data to be ready
#2) Copying the data from the kernel to the process (Copying the data from the kernel to the process) 
 It is important to remember these two points, because the difference between these IO models is that there are different situations in the two phases.
#1. Input operations: read, readv, recv, recvfrom, and recvmsg have a total of 5 functions. If the state is blocked, it will manage two stages of wait data and copy data. If it is set to non-blocking, it will be thrown when wait is not available. exception

#2. Output operation: write, writev, send, sendto, sendmsg has a total of 5 functions. When the send buffer is full, it will block in place. If it is set to non-blocking, an exception will be thrown.

#3. Receive external links: accept, similar to the input operation

#4. Initiate an outgoing link: connect, similar to the output operation
 

 

2 Let's talk about blocking IO first: in this case, there is no way to achieve concurrency, because IO is blocked. The execution will not continue until the IO blocking ends.

From the above figure, we can see that for the blocking IO model. In the process of transferring data, first send a request to the operating system, after waiting for the data, and copying the data.

recv: After local copy data and wait data.

And send: only copy data.

In fact, the copy process is the process from the application to the operating system.

 Therefore, the characteristic of blocking IO is that both stages of IO execution (waiting for data and copying data) are blocked.

    In fact, unless otherwise specified, almost all IO interfaces (including socket interfaces) are blocking. This brings a big problem to network programming. For example, when calling recv(1024), the thread will be blocked. During this period, the thread will not be able to perform any operations or respond to any network requests.

    A simple solution:

# Use multithreading (or multiprocessing) on ​​the server side. The purpose of multithreading (or multiprocessing) is to allow each connection to have its own thread (or process), so that the blocking of any one connection will not affect other connections.

    The problem with this program is:

#Enable multi-process or multi-thread method, when you encounter hundreds or thousands of connection requests at the same time, no matter multi-thread or multi-process will seriously occupy system resources, reduce the system's response efficiency to the outside world, 
and threads and processes themselves It is also easier to enter suspended animation.

    improve proposals:    

#Many programmers may consider using "thread pool" or "connection pool". The "thread pool" is designed to reduce the frequency of thread creation and destruction, maintain a reasonable number of threads, and let idle threads resume new execution tasks. 
The "connection pool" maintains a buffer pool of connections, reuses existing connections as much as possible, and reduces the frequency of creating and closing connections. Both of these two technologies can reduce system overhead very well, and are widely used in many large systems,
such as websphere, tomcat and various databases.

    There are actually problems with the improved solution:

# The "thread pool" and "connection pool" technologies only alleviate the resource occupation caused by frequent calls to the IO interface to a certain extent. Moreover, the so-called "pool" always has its upper limit. When the request greatly exceeds the upper limit, 
the response of the system composed of "pool" to the outside world is not much better than when there is no pool. Therefore, the use of "pool" must consider the size of the response it faces, and adjust the size of the "pool" according to the size of the response.

    Corresponding to the thousands or even tens of thousands of client requests that may appear at the same time in the above example, "thread pool" or "connection pool" may relieve some of the pressure, but it cannot solve all problems. In short, the multi-threaded model can easily and efficiently solve small-scale service requests, but in the face of large-scale service requests, the multi-threaded model will also encounter bottlenecks. Non-blocking interfaces can be used to try to solve this problem.

 

Three multiplexing IO (IO multiplexing)

 The term IO multiplexing may be a bit unfamiliar, but if I say select/epoll, I can probably understand. In some places, this IO method is also called event driven IO (event driven IO). We all know that the advantage of select/epoll is that a single process can handle the IO of multiple network connections at the same time. Its basic principle is that the select/epoll function will continuously poll all the sockets it is responsible for. When a certain socket has data arriving, it will notify the user process. Its process is as follows:

 

 

When the user process calls select, the entire process will be blocked, and at the same time, the kernel will "monitor" all sockets that select is responsible for. When the data in any socket is ready, select will return. At this time, the user process calls the read operation again to copy the data from the kernel to the user process.
    This graph is not much different from the blocking IO graph, in fact it is worse. Because two system calls (select and recvfrom) need to be used here, and blocking IO only calls one system call (recvfrom). However, the advantage of using select is that it can handle multiple connections at the same time.

    emphasize:

    1. If the number of connections processed is not very high, the web server using select/epoll is not necessarily better than the web server using multi-threading + blocking IO, and the delay may be greater. The advantage of select/epoll is not that it can handle a single connection faster, but that it can handle more connections.

    2. In the multiplexing model, for each socket, it is generally set to non-blocking, but, as shown in the figure above, the entire user process is actually blocked all the time. It's just that the process is blocked by the select function, not by socket IO.

    Conclusion: The advantage of select is that it can handle multiple connections, not a single connection  

 Four IO model comparative analysis

 So far, all four IO Models have been introduced. Now go back and answer the first few questions: what is the difference between blocking and non-blocking, and what is the difference between synchronous IO and asynchronous IO.
    Answer the simplest one first: blocking vs non-blocking. In fact, the previous introduction has clearly explained the difference between the two. Calling blocking IO will block the corresponding process until the operation is completed, while non-blocking IO will return immediately when the kernel is still preparing data.

    Before explaining the difference between synchronous IO and asynchronous IO, we need to give the definitions of the two. The definition given by Stevens (actually the POSIX definition) is this:
    A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes;
    An asynchronous I/O operation does not cause the requesting process to be blocked; 
    the difference between the two is that synchronous IO will block the process when it does "IO operation". According to this definition, the four IO models can be divided into two categories. The aforementioned blocking IO, non-blocking IO, and IO multiplexing all belong to the category of synchronous IO, while the latter category of asynchronous I/O.

    Some people may say that non-blocking IO is not blocked. There is a very "cunning" place here. The "IO operation" referred to in the definition refers to the real IO operation, which is the system call of recvfrom in the example. When non-blocking IO executes the recvfrom system call, if the kernel data is not ready, the process will not be blocked at this time. However, when the data in the kernel is ready, recvfrom will copy the data from the kernel to the user memory. At this time, the process is blocked. During this time, the process is blocked. Asynchronous IO is different. When a process initiates an IO operation, it returns directly and ignores it until the kernel sends a signal to tell the process that IO is complete. During this whole process, the process is not blocked at all.

    The comparison of each IO Model is shown in the figure:

    After the above introduction, you will find that the difference between non-blocking IO and asynchronous IO is still obvious. In non-blocking IO, although the process will not be blocked most of the time, it still requires the process to actively check, and when the data preparation is completed, the process also needs to actively call recvfrom again to copy the data to the user memory . And asynchronous IO is completely different. It is like the user process handing over the entire IO operation to someone else (kernel) to complete, and then signaling when the other person is done. During this period, the user process does not need to check the status of IO operations, nor does it need to actively copy data.

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325160515&siteId=291194637