1. 程式人生 > >Async和Await非同步程式設計的原理

Async和Await非同步程式設計的原理

原文地址:http://www.cnblogs.com/ioexception/p/Async_Await_Asynchronous_Programming.html

1. 簡介 

從4.0版本開始.NET引入並行程式設計庫,使用者能夠通過這個庫快捷的開發平行計算和並行任務處理的程式。在4.5版本中.NET又引入了Async和Await兩個新的關鍵字,在語言層面對並行程式設計給予進一步的支援,使得使用者能以一種簡潔直觀的方式實現並行程式設計。因為在很多文件裡針對Async和Await這兩個關鍵字的使用都被稱為非同步程式設計,為了更符合大眾的閱讀習慣,我們使用非同步程式設計這個叫法,意思上和並行程式設計完全一樣。

關於Async和Await非同步程式設計的功能說明和使用介紹,MSDN上有詳細文件,連結如下:

其它地方也可以搜尋到很多相關文章,這裡就不再贅述,本文主要介紹的是非同步程式設計是如何現實的,背後的原理是什麼。

注意:在您閱讀下面內容之前請確保已經熟悉了非同步程式設計的基本方法。

2. .NET中提供新功能的幾種方法

在繼續之前總結一下.NET中提供新功能的三種方法:基於執行時、基於編譯器和基於類庫。

2.1 基於執行時的實現

顯而易見.NET中大多數功能都是基於執行時實現的。比如的類定義的語法、方法的呼叫的語法以及所有基本程式設計語法都有對應的IL程式碼,這也正是定義執行時的內容之一。所以能編譯為對應專有IL程式碼的功能必然是基於執行時實現的。

2.2 基於編譯器

基於編譯器的實現,最常見的例子就是上下文using和yield。上下文using在VB.NET裡乾脆就沒有對應的語法,C#編譯器替你做了你在老版本的C#中或VB.NET裡要做的工作,就是寫try、finally和Dispose語句。提供基於編譯器的新功能微軟不需要修改執行時。

2.3 基於類庫

這個不需要太多解釋,所有的程式語言都是通過庫為開發者提供強大的開發功能的,庫的豐富程度最終決定一個語言的發展前景。

.NET現在常用的執行時只有2.0和4.0兩個版本,3.0 和3.5都是2.0的執行時;4.5的執行時是4.0,它是在編譯器功能和類庫上對4.0的擴充套件。

3. Async和Await的實現

前面提到了yield關鍵字,用於簡化遍歷的實現。如果您熟悉yield這個關鍵字的應用,就會發現await關鍵字的出現位置、使用方式以及執行邏輯和yield是如此的相似。事實的確如此,await和async也是一種基於編譯器的功能(C#和VB.NET都提供了這個功能),不僅如此,它在實現原理上也和yield非常像——await/async和yield都被編譯器在編譯時轉化為了狀態機。

狀態機是一種非常常用的程式設計模式,基本上所有的編譯器都是基於狀態機實現的,當訪問這篇博文的時候瀏覽器就是使用狀態機將從cnblogs.com伺服器上獲取的html文字解析為html元素樹,再繪製到螢幕上。

如何發現或者證實這一點呢,那就是用.NET的反編譯器,每當出現新語法,但凡好奇者都喜歡用反編譯器看一下生成的IL程式碼究竟是什麼樣子。在Reflector被收購收費後(引來吐槽無數),就一直使用JustDecompile(Telerik在Reflector收費後立即推出的免費程式),使用JustDecompile時,需要在該程式的Settings中將Show compiler generated types and members選中。也可以用.NET SDK自帶的ILDASM來反編譯,功能雖然最強大,但是隻能反編譯為IL組合語言,用起來有些不便。

首先,下載MSDN上的示例Async Sample Example from Asynchronous Programming with Async and Await,這是一個簡單的WPF應用,用於演示Async/Await非同步程式設計,主要程式碼如下:

複製程式碼
 1     public partial class MainWindow : Window
 2     {
 3         // Mark the event handler with async so you can use await in it.
 4         private async void StartButton_Click(object sender, RoutedEventArgs e)
 5         {
 6             // Call and await separately.
 7             //Task<int> getLengthTask = AccessTheWebAsync();
 8             //// You can do independent work here.
 9             //int contentLength = await getLengthTask;
10             int contentLength = await AccessTheWebAsync();
11             resultsTextBox.Text +=
12                 String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
13         }
14 
15         // Three things to note in the signature:
16         //  - The method has an async modifier. 
17         //  - The return type is Task or Task<T>. (See "Return Types" section.)
18         //    Here, it is Task<int> because the return statement returns an integer.
19         //  - The method name ends in "Async."
20         async Task<int> AccessTheWebAsync()
21         { 
22             // You need to add a reference to System.Net.Http to declare client.
23             HttpClient client = new HttpClient();
24 
25             // GetStringAsync returns a Task<string>. That means that when you await the
26             // task you'll get a string (urlContents).
27             Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");
28 
29             // You can do work here that doesn't rely on the string from GetStringAsync.
30             DoIndependentWork();
31 
32             // The await operator suspends AccessTheWebAsync.
33             //  - AccessTheWebAsync can't continue until getStringTask is complete.
34             //  - Meanwhile, control returns to the caller of AccessTheWebAsync.
35             //  - Control resumes here when getStringTask is complete. 
36             //  - The await operator then retrieves the string result from getStringTask.
37             string urlContents = await getStringTask;
38 
39             // The return statement specifies an integer result.
40             // Any methods that are awaiting AccessTheWebAsync retrieve the length value.
41             return urlContents.Length;
42         }
43 
44         void DoIndependentWork()
45         {
46             resultsTextBox.Text += "Working . . . . . . .\r\n";
47         }
48     }
複製程式碼

 然後,用JustDecompile開啟生成的AsyncFirstExample.exe。類檢視如下:

這時可以看到,MainWindow類中多出了兩個名稱以u003c開頭的類,這兩個類就是狀態機類,程式碼中有兩個async函式,因此生成了兩個狀態機類。

因為編譯器轉換每個async函式的方式都一樣,所以下面的內容中都以AccessTheWebAsync這個函式為例來說明,該函式對應的狀態機類為u003cAccessTheWebAsyncu003ed__4,反編譯後的C#程式碼如下:

複製程式碼
 1         [CompilerGenerated]
 2         // <AccessTheWebAsync>d__4
 3         private struct u003cAccessTheWebAsyncu003ed__4 : IAsyncStateMachine
 4         {
 5             // <>1__state
 6             public int u003cu003e1__state;
 7 
 8             // <>t__builder
 9             public AsyncTaskMethodBuilder<int> u003cu003et__builder;
10 
11             // <>4__this
12             public MainWindow u003cu003e4__this;
13 
14             // <client>5__5
15             public HttpClient u003cclientu003e5__5;
16 
17             // <getStringTask>5__6
18             public Task<string> u003cgetStringTasku003e5__6;
19 
20             // <urlContents>5__7
21             public string u003curlContentsu003e5__7;
22 
23             // <>u__$awaiter8
24             private TaskAwaiter<string> u003cu003eu__u0024awaiter8;
25 
26             // <>t__stack
27             private object u003cu003et__stack;
28 
29             void MoveNext()
30             {
31                 int <>t__result = 0;
32                 TaskAwaiter<string> u003cu003eu_u0024awaiter8;
33                 try
34                 {
35                     bool <>t__doFinallyBodies = true;
36                     int u003cu003e1_state = this.u003cu003e1__state;
37                     if (u003cu003e1_state != -3)
38                     {
39                         if (u003cu003e1_state == 0)
40                         {
41                             u003cu003eu_u0024awaiter8 = this.u003cu003eu__u0024awaiter8;
42                             TaskAwaiter<string> taskAwaiter = new TaskAwaiter<string>();
43                             this.u003cu003eu__u0024awaiter8 = taskAwaiter;
44                             this.u003cu003e1__state = -1;
45                         }
46                         else
47                         {
48                             this.u003cclientu003e5__5 = new HttpClient();
49                             this.u003cgetStringTasku003e5__6 = this.u003cclientu003e5__5.GetStringAsync("http://msdn.microsoft.com");
50                             this.u003cu003e4__this.DoIndependentWork();
51                             u003cu003eu_u0024awaiter8 = this.u003cgetStringTasku003e5__6.GetAwaiter();
52                             if (!u003cu003eu_u0024awaiter8.IsCompleted)
53                             {
54                                 this.u003cu003e1__state = 0;
55                                 this.u003cu003eu__u0024awaiter8 = u003cu003eu_u0024awaiter8;
56                                 this.u003cu003et__builder.AwaitUnsafeOnCompleted<TaskAwaiter<string>, MainWindow.u003cAccessTheWebAsyncu003ed__4>(ref u003cu003eu_u0024awaiter8, this);
57                                 <>t__doFinallyBodies = false;
58                                 return;
59                             }
60                         }
61                         string result = u003cu003eu_u0024awaiter8.GetResult();
62                         u003cu003eu_u0024awaiter8 = new TaskAwaiter<string>();
63                         this.u003curlContentsu003e5__7 = result;
64                         <>t__result = this.u003curlContentsu003e5__7.Length;
65                     }
66                 }
67                 catch (Exception exception)
68                 {
69                     Exception <>t__ex = exception;
70                     this.u003cu003e1__state = -2;
71                     this.u003cu003et__builder.SetException(<>t__ex);
72                     return;
73                 }
74                 this.u003cu003e1__state = -2;
75                 this.u003cu003et__builder.SetResult(<>t__result);
76             }
77 
78             [DebuggerHidden]
79             void SetStateMachine(IAsyncStateMachine param0)
80             {
81                 this.u003cu003et__builder.SetStateMachine(param0);
82             }
83         }
複製程式碼

關於這個類的命名,C#編譯器命名編譯器生成的類和類成員的方式是:<生成來源名稱>__字尾或輔助說明資訊。尖括號在絕大多數語言中都是運算子,不能用作程式中識別符號的命名,但在IL中,識別符號都以字串的形式儲存在元資料中,通過對映的數字(一般是元資料內的本地偏移地址)來表示識別符號,因此對識別符號的命名基本沒有限制。C#編譯器利用這一點,在編譯器生成的IL程式碼中通過使用<和>來明確區分使用者寫的程式碼和編譯器自動生成的程式碼。

因為<和>不能用在C#的識別符號命名中,反編譯程式JustDecompile對此做出了處理,將<轉換為u003c,>轉換為u003e,也就是Unicode編碼。這樣反編譯出來的程式就能直接拷貝到C#編輯器中使用,但是這個版本的JustDecompile存在一個bug,就是區域性變數中的<和>並沒有被正確的轉換為u003c和u003e,所以生成的程式碼還是不能直接拷貝就用的,當然這並不影響解讀這段程式碼。

類u003cAccessTheWebAsyncu003ed__4實現了介面IAsyncStateMachine,從名字可以看出,這個介面就是為非同步程式設計定義的。這個介面只有兩個方法MoveNext和SetStateMachine,一個典型的狀態機定義:執行下一步和設定狀態。用一個簡單的例子快速梳理一下狀態機的工作過程,以幫助理解非同步程式設計的機制:

一個有1和2兩個有效狀態的狀態機,如果狀態值為1,呼叫MoveNext時狀態機會執行操作A同時將狀態值改為2;如果狀態值為2,呼叫MoveNext時狀態機會執行操作B同時將狀態值改為3;如果狀態值為3,呼叫MoveNext時狀態機不執行任何操作或丟擲異常。

在上面的這個簡單狀態機中,呼叫者不需要知道狀態機下一步要幹什麼,它只被告知在某個時候需要呼叫MoveNext,具體幹什麼由狀態機的內部實現決定,非同步程式設計就是利用的這種模式,通過編譯器對程式碼進行重組,將一個await呼叫前和呼叫後執行的程式碼分配到狀態機的兩個狀態中去執行。如果一個async函式中有兩個await呼叫,那麼生成的狀態機就會有3個狀態,以此類推。如果有迴圈,根據迴圈的位置不同,狀態機狀態轉換更復雜一些。

回過頭來看非同步程式設計中的非同步。在學習使用async/await的時候,很多文件包括msdn都刻意提到async/await關鍵字不會建立新的執行緒,用async關鍵字寫的函式中的程式碼都在呼叫執行緒中執行。這裡是最容易混淆的地方,嚴格意義上這個說法不準確,非同步程式設計必然是多執行緒的。msdn文件裡提到的不會建立新執行緒應該是指async函式本身不會直接在新執行緒中執行。本質上是await呼叫的非同步函式執行完成後回撥狀態機的MoveNext來執行餘下未執行完成的程式碼,await呼叫的非同步函式必然在某個地方——也許是嵌套了很深的一個地方——啟動了一個新的工作執行緒來完成導致我們要使用非同步呼叫的耗時比較長的工作,比如網路內容讀取。

再看u003cAccessTheWebAsyncu003ed__4類的程式碼,u003cu003e1__state這個成員變數很明顯就是狀態值了,在48行到50行,當狀態只不等於-3也不等於0的時候,執行的正好是原始C#程式碼中await語句前面的程式碼,第52行if (!u003cu003eu_u0024awaiter2.IsCompleted)這裡很關鍵,這裡正好是非同步執行最明顯的體現,那就是當主執行緒裡DoIndependentWork()執行結束的時候,另一個執行緒裡獲取http://msdn.microsoft.com頁面內容的工作的也可能已經完成了。如果獲取頁面的工作完成了,就可以直接執行下一狀態要執行的程式碼(62行到64行,原始C#程式碼中await語句後面的代),而不需要進入等待;如果獲取頁面的工作還沒有完成,執行第54到58行程式碼,將當前狀態機與TaskAwaiter繫結,同時將狀態機的狀態值改為0,當非同步函式在另一個執行緒中執行完成時,TaskAwaiter回撥狀態機的MoveNext函式,這時狀態機的狀態為0,執行62到64行程式碼,完成AcessTheWebAsync函式的工作。

可見AcessTheWebAsync函式中原有的程式碼都被編譯器重組到狀態機中了,那麼AcessTheWebAsync函式現在幹什麼?可以猜想到的就是建立狀態機例項,設定初始狀態(不等於-3也不等於0)和啟動狀態機。究竟是不是這樣,來看AcessTheWebAsync反編譯出來的C#程式碼:

複製程式碼
 1         private async Task<int> AccessTheWebAsync()
 2         {
 3             HttpClient httpClient = new HttpClient();
 4             Task<string> stringAsync = httpClient.GetStringAsync("http://msdn.microsoft.com");
 5             this.DoIndependentWork();
 6             string str = await stringAsync;
 7             string str1 = str;
 8             int length = str1.Length;
 9             return length;
10         }
複製程式碼

似乎函式AcessTheWebAsync的程式碼和原始的程式碼一樣,編譯器並沒有做修改,真的是這樣嗎?答案是否定的,原因是JustDecompile這個反編譯器太強大了,它竟然將C#編譯器轉換的程式碼重新還原成async/await語法的程式碼了。所以這裡我們只能看IL程式碼了,切換到IL程式碼,可以看到AcessTheWebAsync編譯後的最終的程式碼如下:

複製程式碼
 1     .method private hidebysig instance class [mscorlib]System.Threading.Tasks.Task`1<int32> AccessTheWebAsync () cil managed 
 2     {
 3         .custom instance void [mscorlib]System.Diagnostics.DebuggerStepThroughAttribute::.ctor() = (
 4             01 00 00 00
 5         )
 6         .custom instance void [mscorlib]System.Runtime.CompilerServices.AsyncStateMachineAttribute::.ctor(class [mscorlib]System.Type) = (
 7             01 00 34 41 73 79 6e 63 46 69 72 73 74 45 78 61
 8             6d 70 6c 65 2e 4d 61 69 6e 57 69 6e 64 6f 77 2b
 9             3c 41 63 63 65 73 73 54 68 65 57 65 62 41 73 79
10             6e 63 3e 64 5f 5f 34 00 00
11         )
12         .locals init (
13             [0] valuetype AsyncFirstExample.MainWindow/'<AccessTheWebAsync>d__4' V_0,
14             [1] class [mscorlib]System.Threading.Tasks.Task`1<int32> V_1,
15             [2] valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> V_2
16         )
17 
18         IL_0000: ldloca.s V_0
19         IL_0002: ldarg.0
20         IL_0003: stfld class AsyncFirstExample.MainWindow AsyncFirstExample.MainWindow/'<AccessTheWebAsync>d__4'::'<>4__this'
21         IL_0008: ldloca.s V_0
22         IL_000a: call valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::Create()
23         IL_000f: stfld valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> AsyncFirstExample.MainWindow/'<AccessTheWebAsync>d__4'::'<>t__builder'
24         IL_0014: ldloca.s V_0
25         IL_0016: ldc.i4.m1
26         IL_0017: stfld int32 AsyncFirstExample.MainWindow/'<AccessTheWebAsync>d__4'::'<>1__state'
27         IL_001c: ldloca.s V_0
28         IL_001e: ldfld valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> AsyncFirstExample.MainWindow/'<AccessTheWebAsync>d__4'::'<>t__builder'
29         IL_0023: stloc.2
30         IL_0024: ldloca.s V_2
31         IL_0026: ldloca.s V_0
32         IL_0028: call instance void valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::Start<valuetype AsyncFirstExample.MainWindow/'<AccessTheWebAsync>d__4'>(!!0&)
33         IL_002d: ldloca.s V_0
34         IL_002f: ldflda valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32> AsyncFirstExample.MainWindow/'<AccessTheWebAsync>d__4'::'<>t__builder'
35         IL_0034: call instance class [mscorlib]System.Threading.Tasks.Task`1<int32> valuetype [mscorlib]System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1<int32>::get_Task()
36         IL_0039: stloc.1
37         IL_003a: br.s IL_003c
38 
39         IL_003c: ldloc.1
40         IL_003d: ret
41     }
複製程式碼

仔細看這段IL彙編程式碼,與原始的C#版的AcessTheWebAsync函式相比幾乎沒有任何相似之處,只有函式的宣告相同,這就是編譯器轉換的結果。人工將這段IL彙編程式碼反編譯成C#:

複製程式碼
 1         [System.Diagnostics.DebuggerStepThrough()]
 2         [System.Runtime.CompilerServices.AsyncStateMachine(typeof(u003cAccessTheWebAsyncu003ed__4))]
 3         private Task<int> AccessTheWebAsync()
 4         {
 5             u003cAccessTheWebAsyncu003ed__4 V_0;
 6             Task<int> V_1;
 7             System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int> V_2;
 8 
 9             V_0.u003cu003e4__this = this;
10             V_0.u003cu003et__builder = System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int>.Create();
11             V_0.u003cu003e1__state = -1;
12             V_2 = V_0.u003cu003et__builder;
13             V_2.Start(ref V_0);
14             V_1 = V_2.Task;
15             return V_1;
16         }
複製程式碼

到這裡已經非常清楚了:AcessTheWebAsync函式首先建立狀態機的例項,因為狀態機類是Struct型別,不需要new;然後,設定相關屬性,狀態機的初始狀態值被設定為-1,符合之前期望的範圍;最後,啟動狀態機,Start方法內部會呼叫一次MoveNext,執行結束後返回Task。

多個async函式之間的呼叫,就是多個狀態機的組合執行。

4. 建立一個真正非同步的非同步函式

前面提到await語句await到最後必然呼叫了一個啟動了新執行緒的完成實際工作的真正非同步的非同步函式,那麼如何自己定義一個這樣的函式呢?其實很簡單,使用System.Threading.Tasks.Task類就可以建立這樣一個函式,示例程式碼如下:

複製程式碼
        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            resultsTextBox.Text += String.Format("\r\nMyAsync({0}).\r\n",
                Thread.CurrentThread.ManagedThreadId); 
            while (true)
                resultsTextBox.Text += String.Format("\r\nMyAsync({0}): {1}.\r\n", 
                    Thread.CurrentThread.ManagedThreadId, await MyAsync());
        }

        public Task<string> MyAsync()
        {
            var t = new Task<string>((str) =>
                {
                    var dt = DateTime.Now;
                    Thread.Sleep(4000);

                    return String.Format("({0}){1} - {2}", 
                        Thread.CurrentThread.ManagedThreadId, dt, DateTime.Now);
                }, null);

            t.Start();
            
            return t;
        }
複製程式碼

執行結果如下:

這個程式是在上述msdn提供的示例的基礎上,向介面中加了一個ID為Button的按鈕,它的事件處理函式為Button_Click,MyAsync就是我們要建立的函式。

在這個真正非同步的函式裡卻看不到Aysnc和Await的影子。由此可見,Aysnc和Await是用來組織非同步函式的呼叫的,實現非同步程式碼和同步程式碼間的無縫互動。

5. 結論 

在.NET 4.5中引入的Async和Await兩個新的關鍵字後,使用者能以一種簡潔直觀的方式實現非同步程式設計。甚至都不需要改變程式碼的邏輯結構,就能將原來的同步函式改造為非同步函式。

在內部實現上,Async和Await這兩個關鍵字由編譯器轉換為狀態機,通過System.Threading.Tasks中的並行類實現程式碼的非同步執行。

最後,一定要確保您的專案的.NET Framework的版本為4.5以上。

2013-07-22 

關於Async/Await的官方部落格:

如回覆中所言,ILSpy確實更好一些,它有一個選項:顯示原始程式碼還是編譯器轉換後的程式碼。這樣,如果用ILSpy,我們就能直接看到AccessTheWebAsync函式被編譯器轉換後的C#程式碼了,而不需要像文中那樣需要人工將IL轉換為C#。

相關推薦

AsyncAwait非同步程式設計原理

原文地址:http://www.cnblogs.com/ioexception/p/Async_Await_Asynchronous_Programming.html 1. 簡介  從4.0版本開始.NET引入並行程式設計庫,使用者能夠通過這個庫快捷的開發平行計算和並行任務

.net4.5使用asyncawait非同步程式設計例項

在.NET4.5中新增了非同步程式設計的新特性async和await,使得非同步程式設計更為簡單。通過特性可以將這項複雜的工作交給編譯器來完成了。之前傳統的方式來實現非同步程式設計較為複雜,這樣對於程式猿來說處理起來比較困難,除錯也沒那麼方便,後續的維護工作也比較痛苦。 A

[C#]非同步程式設計: asyncawait(2)

一、哪裡來的執行緒? async標記的方法的方法體會被編譯到一個內部結構體的MoveNext方法中,有兩個MoveNext呼叫者是來自於主執行緒之外的同一個工作執行緒。 這一個執行緒是何時發起的呢? Task相關的操作有哪些? 1 // 三、理解await 2 bool '<&

[C#]非同步程式設計: asyncawait(1)

[C#]剖析非同步程式設計語法糖: async和await 一、難以被接受的async 自從C#5.0,語法糖大家庭又加入了兩位新成員: async和await。 然而從我知道這兩個傢伙之後的很長一段時間,我甚至都沒搞明白應該怎麼使用它們,這種全新的非同步程式設計模式對於習慣了傳統模式的人來

async await非同步程式設計的學習

      async修改一個方法,表示其為非同步方法。而await表示等待一個非同步任務的執行。js方面,在es7中開始得以支援;而.net在c#5.0開始支援。本文章將分別簡單介紹他們在js和.net中的基本用法。 一、在js中的實現 js中

Asynchronous Programming with async and await (C#)用asyncawait實現非同步程式設計

You can avoid performance bottlenecks and enhance the overall responsiveness of your application by using asynchronous programming. Howe

C#基礎系列:非同步程式設計初探asyncawait

前言:前面有篇從應用層面上面介紹了下多執行緒的幾種用法,有博友就說到了async, await等新語法。確實,沒有非同步的多執行緒是單調的、乏味的,async和await是出現在C#5.0之後,它的出現給了非同步並行變成帶來了很大的方便。非同步程式設計涉及到的東西還

.NET4.5新特性之非同步程式設計AsyncAwait)的使用

一、簡介   首先來看看.net的發展中的各個階段的特性:NET 與C# 的每個版本釋出都是有一個“主題”。即:C#1.0託管程式碼→C#2.0泛型→C#3.0LINQ→C#4.0動態語言→C#4.5非同步程式設計   下面我來簡單的介紹一下非同步程式設計:非同步程式設計,在 .NET Framework

C#基礎系列——非同步程式設計初探:asyncawait

前言:前面有篇從應用層面上面介紹了下多執行緒的幾種用法,有博友就說到了async, await等新語法。確實,沒有非同步的多執行緒是單調的、乏味的,async和await是出現在C#5.0之後,它的出現給了非同步並行變成帶來了很大的方便。非同步程式設計涉及到的東西還是比較多,本篇還是先介紹下async和awa

[你必須知道的非同步程式設計]C# 5.0 新特性——AsyncAwait使非同步程式設計更簡單

本專題概要: 引言 同步程式碼存在的問題 傳統的非同步程式設計改善程式的響應 C# 5.0 提供的async和await使非同步程式設計更簡單  async和await關鍵字剖析 小結 一、引言  在之前的C#基礎知識系列文章中只介紹了從C#1.0到C#

使用 Async Await非同步程式設計

string urlContents = await client.GetStringAsync();以下特徵總結了使上面一個非同步方法。 方法簽名包含一個 Async 或async 修飾符。 非同步方法的名稱以“Async”字尾,按照約定,關閉。 返回型別為下

AsyncAwait如何簡化非同步程式設計,幾個例項讓你徹底明白!

部落格園 引言 C#5.0中async和await兩個關鍵字,這兩個關鍵字簡化了非同步程式設計,之所以簡化了,還是因為編譯器給我們做了更多的工作,下面就具體看看編譯器到底在背後幫我們做了哪些複雜的工作的。 同步程式碼存在的問題 對於同步的程式碼,大家

asyncawait是如何實現非同步程式設計?

目錄 非同步程式設計樣例 樣例解析 淺談Promise如何實現非同步執行 參考 1.非同步程式設計樣例 樣例: // 等待執行函式 function sleep(timeout) { return new Promise((resolve) => { setTimeout(resolv

asyncawait對promise非同步方案的改進,以及使用注意事項

async、await相比原生promise的有優勢: 1.更加簡潔,await一個promise即可,那麼會自動返回這個promise的resolve值,無需在then函式的回撥中手動取值,徹底解決了回撥 //Promise方式 function f() { let promise = new

.NET 4.5 使用asyncawait關鍵字呼叫非同步方法

async和await關鍵字是.NET 4.5新增加的非同步程式設計方式,通過使用這兩個關鍵字可以輕鬆便捷的編寫非同步方法。使用async關鍵字宣告非同步方法,使用await關鍵字等待和獲取非同步方法返回的結果。需要注意的是,一旦聲明瞭await關鍵字,將會阻止當前執行緒直

async await 實現原理

摘要:用序列執行的狀態機模擬實現了非同步 今天在stackOverflow網站看到一個很好的解釋,摘抄併發揮一下, It works similarly to the yield return keyword in C# 2.0. An asynchronous met

.NET 中的 async/await 非同步程式設計

前言 最近在學習Web Api框架的時候接觸到了async/await,這個特性是.NET 4.5引入的,由於之前對於非同步程式設計不是很瞭解,所以花費了一些時間學習一下相關的知識,並整理成這篇部落格,如果在閱讀的過程中發現不對的地方,歡迎大家指正。 同步

解決js非同步問題的方法--asyncawait(ES7)

非同步在給我們解決阻塞的問題時也帶來一些別的問題 開發中呼叫介面經常是非同步的,然後不小心就會犯的錯誤就是介面的資料還沒有返回,我們就當作它已經返回了,然後繼續處理,當然就會發生錯誤。 為了避免資料還沒返回就繼續執行,我們一般會在回掉函式裡面繼續些,但當層次

python教程:使用 async await 協程進行併發程式設計

python 一直在進行併發程式設計的優化, 比較熟知的是使用 thread 模組多執行緒和 multiprocessing 多程序,後來慢慢引入基於 yield 關鍵字的協程。 而近幾個版本,python 對於協程的寫法進行了大幅的優化,很多之前的協程寫法不被官方推薦了。如果你之前瞭解過 python 協程

.NET Web應用中為什麼要使用async/await非同步程式設計

# 前言 1. 什麼是async/await? await和async是.NET Framework4.5框架、C#5.0語法裡面出現的技術,目的是用於簡化非同步程式設計模型。 2. async和await的關係? async和await是成對出現的。 async出現在方法的聲明裡,用於批註一個非同步方法。