How async and await simplify asynchronous programming (several examples let you fully understand)
introduction
Async and await are two keywords in c#5.0. These two keywords simplify asynchronous programming. The reason for the simplification is that the compiler has done more work for us. Let's see what complex work the compiler has done for us.
Problems with synchronization code
We are certainly familiar with synchronized code, because most of the code we usually write is synchronized, but there is a serious problem with synchronized code. For example, when we send a request to a web server, if the code we send the request is synchronized, our application will be in a waiting state, Until a response message is retrieved, however, in this waiting state, the user cannot operate any UI interface and there is no message. If we try to operate the interface, we will see the message "application is response" (next to the application window). I believe that when you use desktop software or access the web, We must have encountered such similar situations. For this, we will certainly feel very uncomfortable. The reason for this is that the code is implemented synchronously, so the interface becomes "stuck" before getting a response message. Therefore, this is certainly unacceptable to users, because if I want to download a large file from the server, we can't even close the form at this time. In order to specify the problems existing in the synchronization code (causing the interface to start), let's see the problem more vividly through a program:
After running the program, when we click the "click me" button on the form, we can't perform any operation on the form, including moving the form, closing the form, etc. the specific running results are as follows:
Traditional asynchronous programming to improve program response
In the above part, we have seen the practical problems caused by the synchronization method. In order to solve similar problems Net framework has long provided support for asynchronous programming, which is used below Net 1.0 to solve the above problems, The specific code is as follows (in the comment part, the synchronization object of the GUI thread is obtained, and then the post method of the synchronization context object is synchronously called to hand over the method to be called to the GUI thread for processing, because the control is originally created by the GUI thread, and then it performs the operation of accessing the control by itself, there is no cross thread problem, and the call is used in the program RichText@R_892_2419 @The invoke method of the control is used to asynchronously callback the method of accessing the control. In fact, the original part behind it is the same as the annotation part. Call RichText@R_892_2419 @The invoke method of the control can be created RichText@R_892_2419 @Control's thread information (that is, the synchronization context of the previous method), and then let the invoke callback method run on this thread):
The results of the run are:
Async and await provided by C # 5.0 make asynchronous programming easier
The above section demonstrates using the traditional asynchronous programming model (APM) to solve the problems of synchronous code NET 2.0,. Net 4.0 and Net 4.5, Microsoft has introduced new ways to solve the problem of synchronous code. They are event based asynchronous mode, task-based asynchronous mode and async and await keywords to support asynchronous programming. The first two asynchronous programming modes are introduced in my previous articles. You can check the relevant articles for details. This section introduces how to realize asynchronous programming with the two keywords async and await in c# 5.0. Let's learn how to use async and await keywords to realize asynchronous programming through the code, and you can also refer to the previous blog to compare and understand that async and await are easier to use for asynchronous programming.
The operation results are as follows:
Analysis of async and await keywords
Let's compare the asynchronous programming code using async and await keywords above with the synchronous code in the second part. Have we found that the asynchronous implementation using async and await keywords is very similar to the implementation of synchronous code, except that there are more async and await keywords in the asynchronous implementation and more async suffixes in the called methods. It is precisely because their implementations are very similar that I named async and await in the fourth part to make asynchronous programming simpler, just as we are writing synchronous code, and the coding idea of the code is the same as that of synchronous code, so as to avoid considering complex problems such as callback entrusted in APM and the definition of various events in EAP.
From the code part, we can see that the use of async and await is indeed very simple. We are like writing synchronous code, but I would like to know what the compiler has done for us? Moreover, from the running results, it can be found that the ID of the thread running the asynchronous method is the same as that of the GUI thread, that is, the asynchronous method runs on the GUI thread, so there is no need to consider cross thread access as in APM (because the callback method is executed on the thread pool thread when the delegated BeginInvoke method is used to callback the method). Let's use the reflection tool to see how the compiler compiles our source code:
Seeing the above code, as a programmer, I want to say - compiler, how can you do this? How can I tamper with my code at will? Isn't this an infringement of my copyright? If you want to change it, you should at least tell me. If my source code sees that its implementation in the compiler is like the above, I believe my source code will say - am I the most vicious person in the world? Well, in order to make you better understand what is done behind the compiler, let's follow the code above. I'll also show you how to play a set of drift boxing to help you find the corresponding relationship between the compiler code and the source code. My analysis idea is:
1. Ask a question - where is the source code of my click event?
From the compiler code, we can see that the first seven sentences of code are assignment operations on a class, and the most real effect is the call of the last start method. A few more questions arise here - D__ What type is 0? < > t in this type__ What exactly is the start method of builder field type used for? With these two questions, we click D__ 0 (the reflection tool allows us to click directly to see) to see what type it is
If you have read my topic on iterators, I'm sure you can think that this structure is an implementation of an iterator, and its main method is the MoveNext method.
The comments from the above code should help us solve the first problem mentioned in the first step, that is < btnclick_ Click>d__ What type is 0? Let's analyze the second problem from < btnclick_ Click>d__ You can find < > t in the code of 0 structure__ The type of builder is asyncvoidmethodbuilder. Let's take a look at the explanation of its start method - run the generator of the associated state machine, that is, call this method to start running the state machine, Running a state machine means executing the MoveNext method (the MoveNext method contains all the code in our source code, which associates the click method generated by the compiler with our source code).
It can be found from the above code comments that when the MoveNext method is called, it will immediately return to the GUI thread. At the same time, there is also such a question: when the MoveNext method is first called, the task must not have been completed, but we output the code in our source code, We must wait for the task to complete (because the task can be transferred to the code in label_007a). At this time, we should call back the MoveNext method to check whether the task is completed (as in the iterator, we need to use the foreach statement to call the MoveNext method all the time), but we can't find any code to call back in the code?
For this question, the callback MoveNext method must exist, but friends who have seen the above code for the first time have not found a similar statement. In the above code comments, I mentioned a problem - what is this code used for? Let's take a look at the following analysis with the problem. In fact, the code below the comment is used to callback the MoveNext method, asyncvoidmethodbuilder Awaitunsafeoncompleted < tawaiter, tstatemachine > method is to schedule the state machine to execute the MoveNext method, which solves the problem of callback to MoveNext.
I believe you can find the corresponding relationship between the source code and the compiler code from the above explanation, but after analyzing the above, I have another question - how to exit the MoveNext method when the task is completed? It can't be called back all the time. As can be seen from the comments of the above code, when the task is completed, the < > 1__ State is set to 0. When the MoveNext method is called back next time, the method will exit directly. However, before the task is completed, it will also set < > 1__ State is set to 0, but the code behind the switch part sets < > 1__ State is set to - 1, which ensures that the MoveNext method can be called back repeatedly before the task is completed. When the task is completed, < > 1__ Code with state set to - 1 will not be executed, but transferred to label_ Part 007a.
After the above analysis, I believe you can also play a trick to analyze the asynchronous method accesswebasync (), which is similar to btnclick_ Click's analysis idea is the same I won't repeat it here
After the analysis, let's share some common questions about async and await
Question 1: does the method with async keyword mean that the method is asynchronous and will not block the thread?
A: No, for a method that only identifies the async keyword (meaning that the await keyword does not appear in the method), the calling thread will execute the method as a synchronous method, so the GUI thread will be blocked. Only when the async keyword and await keyword appear at the same time, the method will be converted to an asynchronous method for processing.
Question 2: will the "async" keyword cause the calling method to run with a thread pool thread?
A: No, the method identified by async keyword will not affect whether the method runs and completes synchronously or asynchronously. Instead, it enables the method to be divided into multiple fragments, some of which may run asynchronously, so the method may complete asynchronously. These fragment boundaries appear inside the method where the "await" keyword is displayed. Therefore, if "await" is not displayed in the method marked "async", the method has only one fragment and will run and complete synchronously. In the await keyword, the front part of the code and the back part of the code are executed synchronously (that is, they are executed on the calling thread, that is, the GUI thread, so there is no problem of cross thread access to the control). The code fragment at the key point of await is executed on the thread of the process pool. The summary is - an asynchronous method implemented using async and await keywords. At this time, the asynchronous method is divided into multiple code fragments to execute, rather than using thread pool threads to execute an entire method like the previous asynchronous programming model (APM) and EAP.
The above is the whole content of this article. I hope it will be helpful to your study, and I hope you can support programming tips.