For a long time, I was not sure whether to use the word "essence". I felt that I was not qualified to say that. In fact, this article explores the differences between synchronization and Asynchronization from another perspective.
In order to analyze the differences between synchronization and Asynchronization, it is also an example of the client sending a request and receiving a response in the previous two articles. If it is a synchronization program, it should be like this (just some pseudo code ):
Socket sock = connectserver (Address); <br/> If (sock = NULL) {<br/> handleconnecterror (); <br/>}< br/> Boolean status = writerequest (request); <br/> If (! Status) {<br/> handlewriteerror (); <br/>}< br/> response = readresponse (); <br/> If (response = NULL) {<br/> handlereaderror (); <br/>}else {<br/> handleresponse (response); <br/>}< br/>
It can be seen that the whole piece of code has multiple function functions, and they are combined into this large piece of code in sequence.
If it is an asynchronous program, it is written like this (it is also pseudo code, but it imitates the Mina program ):
Connectfuture connfuture = connectserver (Address); <br/> connfuture. addlistener (New connectlistener (); <br/> private class connectlistener implements iofuturelistener <connectfuture >{</P> <p> Public void operationcomplete (connectfuture ure future) {</P> <p> If (future. isconnected () {<br/> iosession session = Future. getsession (); <br/> writefuture = writerequest (request); <br/> writefuture. addlistener (New writelistener (); </P> <p >}else {<br/> handleconnecterror (); <br/>}< br/> private class writelistener implements iofuturelistener <writefuture >{< br /> Public void operationcomplete (writefuture future) {<br/> If (future. iswritten () {<br/> // do nothing <br/>} else {<br/> handlewriteerror (); <br/>}</P> <p> public class extends er extends iohandleradapter {<br/> @ override <br/> Public void exceptioncaught (iosession session, throwable cause) {<br/> handlereaderror (); <br/>}< br/> @ override <br/> Public void messagereceived (iosession session, object message) <br/> throws exception {<br/> handleresponse (Message); <br/>}< br/>
In these codes, you can also find the functions that appear in the synchronization code. The difference is that most of these functions become callback. The more significant difference is that, these functions cannot be stored in the same code block in sequence. Therefore, the synchronization mechanism is very complete, and very well-organized code will be broken down in the asynchronous mechanism. This answers the first article.
In the last question, why do people not like to use the asynchronous mechanism, because it is really unfriendly and does not conform to people's general thinking habits.
It's interesting to think about what happened when the Code was executed.
Let's start with the synchronization code. When the code executes the connectserver function, the program tries to connect to a remote server. During this period, the thread is blocked, so the kernel suspends the thread, save some context (such as registers) during thread running in a certain place and run another thread. After the connection is successful, the thread is awakened and its context is restored, then continue running. Similarly, when running to readresponse (), the kernel reads data from the NIC buffer. At this time, the data has not arrived, so it suspends the thread, switches and saves the context, then run another thread. When there is data in the NIC buffer, the thread is awakened, the context is restored, and then continues to run.
What if it is an asynchronous program? For example, if a connectfuture is returned after the connectserver is executed, the connection is not completed yet. Therefore, we register a callback function connectlistener with Mina, which tells Mina to call the writerequest function after the connection is complete. There is a problem here. How does Mina know which socket should writerequest write data? The trick is that connectfuture is returned by the connectserver. It is passed into the callback function as a parameter, and the socket corresponding to the target server is saved in connectfuture (that is, the session in our code ).
For example, after a request is written, Mina receives response through the SELECT statement of Java NiO. when data is written into the socket, messagereceived is called. But how does this function know from which socket the message is read? Because Mina writes the corresponding socket as the parameter. So how does Mina know which request the message is read? Mina won't know, so, just as the second article
In this case, we must maintain an ID number and find the corresponding request through the ID number.
Okay, I admit that the above paragraphs are quite messy. Let me straighten out my ideas. For synchronous programs, only one thread needs to execute all functional functions in sequence. During the execution process, once the thread is blocked, it will be suspended by the kernel, the kernel is responsible for switching the context of the thread until it can continue. For Asynchronous programs, the entire code will be cut into different functional functions as Callback, And the execution sequence between them is not guaranteed. Secondly, there will not be only one thread to complete all the tasks, for example, in the second article
In hadoop RPC, read and write are completed by two threads respectively. In Mina, there are also a certain number of worker threads, the preceding callback functions may be executed by different threads. Finally, even if these callback functions are executed by different threads, context switching also occurs. For example, you must tell connectlistener which socket connection is successful, and tell messagereceived which socket reads data. Tell handleresponse which request the response corresponds, however, unlike the synchronization mechanism, context switching is completed by a program that provides an asynchronous mechanism (such as Mina, such as hadoop RPC), rather than by the kernel.
To be continued ~