Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to understand Async and Await, the new features of C # 5.0

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

Today, I will talk to you about how to understand Async and Await, the new features of C # 5.0. maybe many people don't know much about it. In order to make you understand better, the editor has summarized the following content for you. I hope you can get something according to this article.

I. introduction

In the previous series of articles on basic knowledge of C #, only the main features in C # 1.0 to C # 4.0 were introduced. However, with the introduction of .NET 4.5, new features have been added to C #-- the keywords async and await in C # 5.0, which simplify asynchronous programming because the compiler has done more work for us. Let's take a look at what complicated work the compiler has done for us behind our backs.

Second, the problems existing in synchronization code

We are certainly no stranger to synchronous code, because most of the code we usually write is synchronous, but there is a serious problem with synchronous code. For example, when we send a request to a Web server, if the code we make the request is implemented synchronously, our application will wait until a response message is retrieved. However, in this waiting state, for the user can not operate any UI interface and there is no message, if we try to operate the interface, we will see the "application responds" message (next to the application window). I believe that everyone must have encountered such a similar situation when using desktop software or visiting web. People are sure to look very uncomfortable. The reason for this is because the implementation of the code is implemented synchronously, so the interface becomes a "stuck" state before getting a response message, so this must be unacceptable to the user. 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 specifically illustrate the problem with the synchronization code (causing the interface to start), let's use a program to get a better look at the problem:

/ / Click the event private void btnClick_Click (object sender, EventArgs e) {this.btnClick.Enabled = false; long length = AccessWeb (); this.btnClick.Enabled = true; / / you can do some operations that do not depend on reply OtherWork () This.richTextBox1.Text + = String.Format ("\ nThe length of bytes replied is: {0}.\ r\ n", length); txbMainThreadID.Text = Thread.CurrentThread.ManagedThreadId.ToString ();} private long AccessWeb () {MemoryStream content = new MemoryStream () / / one pair of MSDN initiates a Web request HttpWebRequest webRequest = WebRequest.Create ("http://msdn.microsoft.com/zh-cn/") as HttpWebRequest" If (webRequest! = null) {/ / returns the reply result using (WebResponse response = webRequest.GetResponse ()) {using (Stream responseStream = response.GetResponseStream ()) {responseStream.CopyTo (content) } txbAsynMethodID.Text = Thread.CurrentThread.ManagedThreadId.ToString (); return content.Length;}

After running the program, after we click the "Click me" button on the form, we cannot do anything on the form, including moving the form, closing the form, etc., until we get the server's response. The specific results are as follows:

Third, traditional asynchronous programming to improve the response of the program

In the above section, we have seen the practical problems brought about by synchronous methods. in order to solve similar problems,. NET Framework has provided support for asynchronous programming a long time ago, so let's use the asynchronous programming model (APM) proposed in .NET 1.0 to solve the above problems. The specific code is as follows. (the annotated part gets the synchronization object of the GUI thread. Then synchronously call the post method of the synchronous context object to give the method to be called to the Gui thread to handle, because the control is originally created by the GUI thread, and then it does not have the problem of cross-thread when it performs the operation of accessing the control. The program uses the Invoke method of calling the RichTextBox control to asynchronously call back the method to access the control. In fact, the original behind the control is the same as the comment part. Call the Invoke method of the RichTextBox control to get the thread information for creating the RichTextBox control (that is, the synchronization context of the former way), and then let the method of the Invoke callback run on that thread:

Private void btnClick_Click (object sender, EventArgs e) {this.richTextBox1.Clear (); btnClick.Enabled = false; AsyncMethodCaller caller = new AsyncMethodCaller (TestMethod); IAsyncResult result = caller.BeginInvoke (GetResult, null); / capture the synchronization context derived object of the calling thread / / sc= SynchronizationContext.Current } # region uses APM to implement asynchronous programming / / synchronous method private string TestMethod () {/ / simulate doing some time-consuming operations / / actual projects may read a large file or get data from a remote server, etc. For (int I = 0; I

< 10; i++) { Thread.Sleep(200); } return "点击我按钮事件完成"; } // 回调方法 private void GetResult(IAsyncResult result) { AsyncMethodCaller caller = (AsyncMethodCaller)((AsyncResult)result).AsyncDelegate; // 调用EndInvoke去等待异步调用完成并且获得返回值 // 如果异步调用尚未完成,则 EndInvoke 会一直阻止调用线程,直到异步调用完成 string resultvalue = caller.EndInvoke(result); //sc.Post(ShowState,resultvalue); richTextBox1.Invoke(showStateCallback, resultvalue); } // 显示结果到richTextBox private void ShowState(object result) { richTextBox1.Text = result.ToString(); btnClick.Enabled = true; } // 显示结果到richTextBox //private void ShowState(string result) //{ // richTextBox1.Text = result; // btnClick.Enabled = true; //} #endregion 运行的结果为:

4. Async and await provided by C # 5.0 make asynchronous programming easier.

The above section demonstrates the use of the traditional asynchronous programming model (APM) to solve the problems of synchronous code. However, in .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 provide async and await keywords to support asynchronous programming. About the first two asynchronous programming modes, have been introduced in my previous article, you can check the relevant articles to understand in detail, this section on the C # 5.0 of the two keywords async and await how to achieve asynchronous programming to introduce to you. Here's how to use the async and await keywords to implement asynchronous programming, and you can also refer to the previous blog to compare and understand that using async and await is easier to program asynchronously.

Private async void btnClick_Click (object sender, EventArgs e) {long length = await AccessWebAsync (); / / you can do some operations that do not depend on replies here OtherWork (); this.richTextBox1.Text + = String.Format ("\ nThe byte length of the reply is: {0}.\ r\ n", length) TxbMainThreadID.Text = Thread.CurrentThread.ManagedThreadId.ToString ();} / / define asynchronous methods using the async and await keywords provided in C # 5.0 / / you can see from the code that defining asynchronous methods in Cnotify 5.0 is as simple as defining synchronous methods. Defining an asynchronous method using async and await does not create a new thread, / / it runs on an existing thread to perform multiple tasks. / / I don't know if you have any questions at this time? When running a time-consuming operation on an existing thread (that is, the UI thread), / / Why doesn't the UI thread be blocked? / / the answer to this question is that when the compiler sees the await keyword, the thread will private async Task AccessWebAsync () {MemoryStream content = new MemoryStream (); / / A pair of MSDN will initiate a Web request HttpWebRequest webRequest = WebRequest.Create ("http://msdn.microsoft.com/zh-cn/") as HttpWebRequest" If (webRequest! = null) {/ / returns the reply result using (WebResponse response = await webRequest.GetResponseAsync ()) {using (Stream responseStream = response.GetResponseStream ()) {await responseStream.CopyToAsync (content) } txbAsynMethodID.Text = Thread.CurrentThread.ManagedThreadId.ToString (); return content.Length } private void OtherWork () {this.richTextBox1.Text + = "\ r\ nwaiting for the server to reply.\ n";}

The running results are as follows:

V. Analysis of async and await keywords

We compare the code that uses the async and await keywords to achieve asynchronous programming above and the synchronous code in the second part, do you find that the asynchronous implementation using the async and await keywords is very similar to the synchronous code implementation, except that the asynchronous implementation has more async and await keywords and calling methods with more async suffixes. It is precisely because their implementations are very similar that in the fourth part I named using async and await to make asynchronous programming easier, just as we are writing synchronous code, and the coding idea of the code is the same as synchronous code, so as to avoid thinking about complex issues such as callbacks to delegates in APM, as well as various event definitions in EAP. We can see from the code section that the use of async and await is really simple, it's like writing synchronous code, but I wonder what the compiler has done for us. And from the running results, we can find that the thread running the asynchronous method is the same as the ID 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 when the callback method is made through the delegate's BeginInvoke method, the callback method is executed on the thread pool thread). Let's use the reflection tool to see how the compiler compiles our source code:

For the code for the button click event, the code behind the compiler is like this, exactly like the two in our source code:

/ / the code generated by the compiler for the button Click event private void btnClick_Click (object sender, EventArgs e) {dashes 0 dudes; d__.4__this = this; d__.sender = sender; dudes. E = e; d__.t__builder = AsyncVoidMethodBuilder.Create (); d__.1__state =-1; d__.t__builder.Start (ref dashes _) }

Seeing the code above, as a programmer, I want to say-- how could you do this to the compiler? How can I tamper with my code at will? Isn't that an infringement of my copyright? If you want to change it, you should at least let me know. If my source code sees that it is implemented like that in the compiler, I believe my source code will say-- have I been caught by the most vicious face in the world? Well, in order to better understand what's going on behind the compiler, let's follow the code above, and I'll show you a set of floating punches to help you find the relationship between the compiler code and the source code. My analytical ideas are as follows:

1. Ask the question-- where is the source code for my click event? From the compiler code, we can see that the first seven sentences of code are all operations that assign values to a class, and what really works is the last call to the Start method. A few more questions have arisen here-what is the type of dazzling zero? What exactly is the Start method of the t__builder field type in this type for? With these two questions, let's click on dumbbell 0 (the reflection tool allows us to click directly) to see what type it is.

/ / the definition of the dumped _ 0 type, you can see from the following code that it is a structure / / this type is an embedded type generated by the compiler / / does the implementation of this type remind you of anything? Private struct rules 0: IAsyncStateMachine {/ / Fields public int 1 states; public Form1 4 states; public AsyncVoidMethodBuilder tacks buildings; private object tacks stacks; private TaskAwaiter utilisation packages awaiter2; public long 5 states 1; public EventArgs e; public object sender; / / Methods private void MoveNext () {try {TaskAwaiter CS$0 $0001 Bool t__doFinallyBodies = true; switch (this.1__state) {case-3: goto Label_010E; case 0: break; default: / / gets the waiters used to wait for the Task (task). If you want to know whether a task is completed or not, we need a waiter object to monitor the task, so Microsoft defines a wait object's / / you can see from this In fact, the implementation principle behind the async and await keywords is task-based asynchronous programming mode (TAP) / / here the code is CS$0 $0001 = this.4__this.AccessWebAsync () .GetAwaiter () running on thread pool threads. / / if the task is completed, go to the code if (CS$0 $0001.IsCompleted) {goto Label_007A;} / / in the Label_007A section and set the status to 0 in order to exit the callback method. This.1__state = 0; this.u__$awaiter2 = CS$0 $0001; / / what is this code for? Let's take a look at the following analysis this.t__builder.AwaitUnsafeOnCompleted (ref CS$0 $0001, ref this); t__doFinallyBodies = false; / / returns to the calling thread, that is, the gui thread, which is why this method does not block the gui thread, returning to the GUI thread return regardless of whether the task is completed or not } / / when the task is completed, the following code will not be executed, but the code CS$0 $0001 = this.u__$awaiter2; this.u__$awaiter2 = new TaskAwaiter () in Label_007A will be executed directly; / / in order to call back the MoveNext code this.1__state =-1 again Label_007A: / / the following code is CS$0 $0001 = new TaskAwaiter () executed on the Gui thread; long CS$0 $0003 = CS$0 $0001.GetResult (); this.5__1 = CS$0 $0003; / / the code in our source code here is this.4__this.OtherWork () This.4__this.richTextBox1.Text = this.4__this.richTextBox1.Text + string.Format ("\ nThe length of bytes replied is: {0}.\ r\ n", this.5__1); this.4__this.txbMainThreadID.Text = Thread.CurrentThread.ManagedThreadId.ToString () } catch (Exception t__ex) {this.1__state =-2; this.t__builder.SetException (t__ex); return;} Label_010E: this.1__state =-2; this.t__builder.SetResult () } [DebuggerHidden] private void SetStateMachine (IAsyncStateMachine param0) {this.t__builder.SetStateMachine (param0);}}

If you have seen my iterator project, I am sure you can think of this structure as an implementation of an iterator, the main method of which is the MoveNext method. The comments from the above code should help us solve the first question mentioned in the first step, that is, what type droomroom0 is.

Let's analyze the second question. You can find that the type of t__builder is of type AsyncVoidMethodBuilder from the code of the diteriter0 structure. let's take a look at the interpretation of its Start method-- run the generator of the associated state machine, that is, you can call this method to start running the state machine, which refers to the execution of the MoveNext method (the MoveNext method has all the code in our source code, so the compiler-generated Click method is associated with our source code). From the above code comments, we can see that when the MoveNext is called, it will immediately return to the GUI thread, and there is also a doubt that when the MoveNext method is first called, the task must not have been completed, but we output the code in our source code and must wait for the task to be completed (because the task is completed before it can be transferred to the code in Label_007A). At this point, we should need to 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 didn't find any code for the callback in the code? For this question, there must be a callback MoveNext method, but friends who look at the above code for the first time have not found a similar statement. I raised a question in the above code comments-what is this code for? Let's take a look at the following analysis with the problem. In fact, the code below is used to call back the MoveNext method, and the AsyncVoidMethodBuilder.AwaitUnsafeOnCompleted method is to schedule the state machine to execute the MoveNext method, thus solving the question of callback MoveNext.

I believe you can find the correspondence 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? You can't let it be called back all the time. As can be seen from the comments in the above code, when the task is completed, the 1__state will be set to 0, and the next time the MoveNext method will be called back, the method will exit directly. However, before the task is completed, the 1__state will also be set to 0, but the code behind the Switch section will set the 1__state to-1, which ensures that before the task is completed. The MoveNext method can be called back repeatedly, and when the task is completed, the code with 1__state set to-1 will not be executed, but will be transferred to the Label_007A section.

After the above analysis, I believe you can also come up with a set of floating fists to analyze the asynchronous method AccessWebAsync (), which is the same as that of btnClick_Click. There will be no repetition here.

After the analysis, let's share a few frequently asked questions about async and await

Question 1: does the method with the async keyword mean that the method is asynchronous and will not block the thread?

Answer: no, for a method that only identifies the async keyword (meaning that there is no await keyword in the method), the calling thread executes the method as if it were synchronous, so the gui thread is blocked, and the method is converted to asynchronous processing only when the async and await lightsabers appear at the same time.

Question 2: does the "async" keyword cause the calling method to run with thread pool threads?

Answer: no, the method identified by the async keyword does not affect whether the method runs synchronously or asynchronously, but rather, it enables the method to be split into multiple fragments, some of which may run asynchronously, so that the method may be completed asynchronously. These fragment boundaries appear within the method where the "await" keyword is used. So, if the use of "await" is not shown in the method marked "async", then the method has only one fragment and will be run and completed synchronously. The first part of the code and the second part of the code that appears in the await keyword are executed synchronously (that is, on the calling thread, that is, the GUI thread, so there is no problem of cross-thread access to the control), and the code snippet at the await key is executed on the thread pool thread. To sum up-- an asynchronous method implemented using the async and await keywords, where the asynchronous method is divided into code snippets to execute instead of using thread pool threads to execute an entire method, as in the previous asynchronous programming model (APM) and EAP.

After reading the above, do you have any further understanding of how to understand Async and Await, the new features of C # 5.0? If you want to know more knowledge or related content, please follow the industry information channel, thank you for your support.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report