日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線(xiàn)溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
C#5.0新特性:Async和Await使異步編程更簡(jiǎn)單

一、引言

創(chuàng)新互聯(lián)2013年至今,先為善左等服務(wù)建站,善左等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢(xún)服務(wù)。為善左企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。

在之前的C#基礎(chǔ)知識(shí)系列文章中只介紹了從C#1.0到C#4.0中主要的特性,然而.NET 4.5 的推出,對(duì)于C#又有了新特性的增加——就是C#5.0中async和await兩個(gè)關(guān)鍵字,這兩個(gè)關(guān)鍵字簡(jiǎn)化了異步編程,之所以簡(jiǎn)化了,還是因?yàn)榫幾g器給我們做了更多的工作,下面就具體看看編譯器到底在背后幫我們做了哪些復(fù)雜的工作的。

二、同步代碼存在的問(wèn)題

對(duì)于同步的代碼,大家肯定都不陌生,因?yàn)槲覀兤匠?xiě)的代碼大部分都是同步的,然而同步代碼卻存在一個(gè)很?chē)?yán)重的問(wèn)題,例如我們向一個(gè)Web服務(wù)器發(fā)出一個(gè)請(qǐng)求時(shí),如果我們發(fā)出請(qǐng)求的代碼是同步實(shí)現(xiàn)的話(huà),這時(shí)候我們的應(yīng)用程序就會(huì)處于等待狀態(tài),直到收回一個(gè)響應(yīng)信息為止,然而在這個(gè)等待的狀態(tài),對(duì)于用戶(hù)不能操作任何的UI界面以及也沒(méi)有任何的消息,如果我們?cè)噲D去操作界面時(shí),此時(shí)我們就會(huì)看到"應(yīng)用程序?yàn)轫憫?yīng)"的信息(在應(yīng)用程序的窗口旁),相信大家在平常使用桌面軟件或者訪(fǎng)問(wèn)web的時(shí)候,肯定都遇到過(guò)這樣類(lèi)似的情況的,對(duì)于這個(gè),大家肯定會(huì)覺(jué)得看上去非常不舒服。引起這個(gè)原因正是因?yàn)榇a的實(shí)現(xiàn)是同步實(shí)現(xiàn)的,所以在沒(méi)有得到一個(gè)響應(yīng)消息之前,界面就成了一個(gè)"卡死"狀態(tài)了,所以這對(duì)于用戶(hù)來(lái)說(shuō)肯定是不可接受的,因?yàn)槿绻乙獜姆?wù)器上下載一個(gè)很大的文件時(shí),此時(shí)我們甚至不能對(duì)窗體進(jìn)行關(guān)閉的操作的。為了具體說(shuō)明同步代碼存在的問(wèn)題(造成界面開(kāi)始),下面通過(guò)一個(gè)程序讓大家更形象地看下問(wèn)題所在:

 
 
 
 
  1. // 單擊事件
  2.         private void btnClick_Click(object sender, EventArgs e)
  3.         {
  4.             this.btnClick.Enabled = false;
  5.             long length = AccessWeb();
  6.             this.btnClick.Enabled = true;
  7.             // 這里可以做一些不依賴(lài)回復(fù)的操作
  8.             OtherWork();
  9.             this.richTextBox1.Text += String.Format("\n 回復(fù)的字節(jié)長(zhǎng)度為:  {0}.\r\n", length);
  10.             txbMainThreadID.Text = Thread.CurrentThread.ManagedThreadId.ToString();
  11.         }
  12.         private  long AccessWeb()
  13.         {
  14.             MemoryStream content = new MemoryStream();
  15.             // 對(duì)MSDN發(fā)起一個(gè)Web請(qǐng)求
  16.             HttpWebRequest webRequest = WebRequest.Create("http://msdn.microsoft.com/zh-cn/") as HttpWebRequest;
  17.             if (webRequest != null)
  18.             {
  19.                 // 返回回復(fù)結(jié)果
  20.                 using (WebResponse response = webRequest.GetResponse())
  21.                 {
  22.                     using (Stream responseStream = response.GetResponseStream())
  23.                     {
  24.                         responseStream.CopyTo(content);
  25.                     }
  26.                 }
  27.             }
  28.             txbAsynMethodID.Text = Thread.CurrentThread.ManagedThreadId.ToString();
  29.             return content.Length;
  30.         }

運(yùn)行程序后,當(dāng)我們點(diǎn)擊窗體的 "點(diǎn)擊我"按鈕之后,在得到服務(wù)器響應(yīng)之前,我們不能對(duì)窗體進(jìn)行任何的操作,包括移動(dòng)窗體,關(guān)閉窗體等,具體運(yùn)行結(jié)果如下:

三、傳統(tǒng)的異步編程來(lái)改善程序的響應(yīng)

 上面部分我們已經(jīng)看到同步方法所帶來(lái)的實(shí)際問(wèn)題了,為了解決類(lèi)似的問(wèn)題,.NET Framework很早就提供了對(duì)異步編程的支持,下面就用.NET 1.0中提出的異步編程模型(APM)來(lái)解決上面的問(wèn)題,具體代碼如下(注釋的部分通過(guò)獲得GUI線(xiàn)程的同步上文對(duì)象,然后同步調(diào)用同步上下文對(duì)象的post方法把要調(diào)用的方法交給GUI線(xiàn)程去處理,因?yàn)榭丶緛?lái)就是由GUI線(xiàn)程創(chuàng)建的,然后由它自己執(zhí)行訪(fǎng)問(wèn)控件的操作就不存在跨線(xiàn)程的問(wèn)題了,程序中使用的是調(diào)用RichTextBox控件的Invoke方式來(lái)異步回調(diào)訪(fǎng)問(wèn)控件的方法,其實(shí)背后的原來(lái)和注釋部分是一樣的,調(diào)用RichTextBox控件的Invoke方法可以獲得創(chuàng)建RichTextBox控件的線(xiàn)程信息(也就是前一種方式的同步上下文),然后讓Invoke回調(diào)的方法在該線(xiàn)程上運(yùn)行):

 
 
 
 
  1. private void btnClick_Click(object sender, EventArgs e)
  2.         {
  3.             this.richTextBox1.Clear();
  4.             btnClick.Enabled = false;
  5.             AsyncMethodCaller caller = new AsyncMethodCaller(TestMethod);
  6.             IAsyncResult result = caller.BeginInvoke(GetResult, null);
  7.             //// 捕捉調(diào)用線(xiàn)程的同步上下文派生對(duì)象
  8.             //sc= SynchronizationContext.Current;
  9.         }
  10.    
  11.         # region 使用APM實(shí)現(xiàn)異步編程
  12.         // 同步方法
  13.         private string TestMethod()
  14.         {       
  15.             // 模擬做一些耗時(shí)的操作
  16.             // 實(shí)際項(xiàng)目中可能是讀取一個(gè)大文件或者從遠(yuǎn)程服務(wù)器中獲取數(shù)據(jù)等。
  17.             for (int i = 0; i < 10; i++)
  18.             {
  19.                 Thread.Sleep(200);
  20.             }
  21.             return "點(diǎn)擊我按鈕事件完成";
  22.         }
  23.        
  24.         // 回調(diào)方法
  25.         private void GetResult(IAsyncResult result)
  26.         {
  27.             AsyncMethodCaller caller = (AsyncMethodCaller)((AsyncResult)result).AsyncDelegate;
  28.             // 調(diào)用EndInvoke去等待異步調(diào)用完成并且獲得返回值
  29.             // 如果異步調(diào)用尚未完成,則 EndInvoke 會(huì)一直阻止調(diào)用線(xiàn)程,直到異步調(diào)用完成
  30.             string resultvalue = caller.EndInvoke(result);
  31.             //sc.Post(ShowState,resultvalue);
  32.             richTextBox1.Invoke(showStateCallback, resultvalue);
  33.         }
  34.         // 顯示結(jié)果到richTextBox
  35.         private void ShowState(object result)
  36.         {
  37.             richTextBox1.Text = result.ToString();
  38.             btnClick.Enabled = true;
  39.         }
  40.         // 顯示結(jié)果到richTextBox
  41.         //private void ShowState(string result)
  42.         //{
  43.         //    richTextBox1.Text = result;
  44.         //    btnClick.Enabled = true;
  45.         //}
  46.         #endregion

運(yùn)行的結(jié)果為:

#p#

四、C# 5.0 提供的async和await使異步編程更簡(jiǎn)單

上面部分演示了使用傳統(tǒng)的異步編程模型(APM)來(lái)解決同步代碼所存在的問(wèn)題,然而在.NET 2.0,.NET 4.0和.NET 4.5中,微軟都有推出新的方式來(lái)解決同步代碼的問(wèn)題,他們分別為基于事件的異步模式,基于任務(wù)的異步模式和提供async和await關(guān)鍵字來(lái)對(duì)異步編程支持。關(guān)于前兩種異步編程模式,在我前面的文章中都有介紹,大家可以查看相關(guān)文章進(jìn)行詳細(xì)地了解,本部分就C# 5.0中的async和await這兩個(gè)關(guān)鍵字如何實(shí)現(xiàn)異步編程的問(wèn)題來(lái)給大家介紹下。下面通過(guò)代碼來(lái)了解下如何使用async和await關(guān)鍵字來(lái)實(shí)現(xiàn)異步編程,并且大家也可以參看前面的博客來(lái)對(duì)比理解使用async和await是異步編程更簡(jiǎn)單。

 
 
 
 
  1. private async void btnClick_Click(object sender, EventArgs e)
  2.         {
  3.             long length = await AccessWebAsync();
  4.            
  5.             // 這里可以做一些不依賴(lài)回復(fù)的操作
  6.             OtherWork();
  7.             this.richTextBox1.Text += String.Format("\n 回復(fù)的字節(jié)長(zhǎng)度為:  {0}.\r\n", length);
  8.             txbMainThreadID.Text = Thread.CurrentThread.ManagedThreadId.ToString();
  9.         }
  10.         // 使用C# 5.0中提供的async 和await關(guān)鍵字來(lái)定義異步方法
  11.         // 從代碼中可以看出C#5.0 中定義異步方法就像定義同步方法一樣簡(jiǎn)單。
  12.         // 使用async 和await定義異步方法不會(huì)創(chuàng)建新線(xiàn)程,
  13.         // 它運(yùn)行在現(xiàn)有線(xiàn)程上執(zhí)行多個(gè)任務(wù).
  14.         // 此時(shí)不知道大家有沒(méi)有一個(gè)疑問(wèn)的?在現(xiàn)有線(xiàn)程上(即UI線(xiàn)程上)運(yùn)行一個(gè)耗時(shí)的操作時(shí),
  15.         // 為什么不會(huì)堵塞UI線(xiàn)程的呢?
  16.         // 這個(gè)問(wèn)題的答案就是 當(dāng)編譯器看到await關(guān)鍵字時(shí),線(xiàn)程會(huì)
  17.         private async Task AccessWebAsync()
  18.         {
  19.             MemoryStream content = new MemoryStream();
  20.             // 對(duì)MSDN發(fā)起一個(gè)Web請(qǐng)求
  21.             HttpWebRequest webRequest = WebRequest.Create("http://msdn.microsoft.com/zh-cn/") as HttpWebRequest;
  22.             if (webRequest != null)
  23.             {
  24.                 // 返回回復(fù)結(jié)果
  25.                 using (WebResponse response = await webRequest.GetResponseAsync())
  26.                 {
  27.                     using (Stream responseStream = response.GetResponseStream())
  28.                     {
  29.                         await responseStream.CopyToAsync(content);
  30.                     }
  31.                 }
  32.             }
  33.             txbAsynMethodID.Text = Thread.CurrentThread.ManagedThreadId.ToString() ;
  34.             return content.Length;
  35.         }
  36.         private void OtherWork()
  37.         {
  38.             this.richTextBox1.Text += "\r\n等待服務(wù)器回復(fù)中.................\n";
  39.         }

運(yùn)行結(jié)果如下:

五、async和await關(guān)鍵字剖析

我們對(duì)比下上面使用async和await關(guān)鍵字來(lái)實(shí)現(xiàn)異步編程的代碼和在第二部分的同步代碼,有沒(méi)有發(fā)現(xiàn)使用async和await關(guān)鍵字的異步實(shí)現(xiàn)和同步代碼的實(shí)現(xiàn)很像,只是異步實(shí)現(xiàn)中多了async和await關(guān)鍵字和調(diào)用的方法都多了async后綴而已。正是因?yàn)樗麄兊膶?shí)現(xiàn)很像,所以我在第四部分才命名為使用 async和await使異步編程更簡(jiǎn)單,就像我們?cè)趯?xiě)同步代碼一樣,并且代碼的coding思路也是和同步代碼一樣,這樣就避免考慮在APM中委托的回調(diào)等復(fù)雜的問(wèn)題,以及在EAP中考慮各種事件的定義。從代碼部分我們可以看出async和await的使用確實(shí)很簡(jiǎn)單,我們就如在寫(xiě)同步代碼一般,但是我很想知道編譯器到底給我們做了怎樣的處理的?并且從運(yùn)行結(jié)果可以發(fā)現(xiàn),運(yùn)行異步方法的線(xiàn)程和GUI線(xiàn)程的ID是一樣的,也就是說(shuō)異步方法的運(yùn)行在GUI線(xiàn)程上,所以就不用像APM中那樣考慮跨線(xiàn)程訪(fǎng)問(wèn)的問(wèn)題了(因?yàn)橥ㄟ^(guò)委托的BeginInvoke方法來(lái)進(jìn)行回調(diào)方法時(shí),回調(diào)方法是在線(xiàn)程池線(xiàn)程上執(zhí)行的)。下面就用反射工具看看編譯器把我們的源碼編譯成什么樣子的:

對(duì)于按鈕點(diǎn)擊事件的代碼來(lái)說(shuō),編譯器生成的背后代碼卻是下面這樣的,完全和我們?cè)创a中的兩個(gè)樣:

 
 
 
 
  1. // 編譯器為按鈕Click事件生成的代碼
  2. private void btnClick_Click(object sender, EventArgs e)
  3. {
  4.     d__0 d__;
  5.     d__.<>4__this = this;
  6.     d__.sender = sender;
  7.     d__.e = e;
  8.     d__.<>t__builder = AsyncVoidMethodBuilder.Create();
  9.     d__.<>1__state = -1;
  10.     d__.<>t__builder.Start<d__0>(ref d__);
  11. }

看到上面的代碼,作為程序員的我想說(shuō)——編譯器你怎么可以這樣呢?怎么可以任意篡改我的代碼呢?這樣不是侵犯我的版權(quán)了嗎?你要改最起碼應(yīng)該告訴我一聲吧,如果我的源碼看到它在編譯器中的實(shí)現(xiàn)是上面那樣的,我相信我的源碼會(huì)說(shuō)——難道我中了世間上最?lèi)憾镜拿婺咳悄_嗎? 好吧,為了讓大家更好地理清編譯器背后到底做了什么事情,下面就順著上面的代碼摸瓜,我也來(lái)展示耍一套還我漂漂拳來(lái)幫助大家找到編譯器代碼和源碼的對(duì)應(yīng)關(guān)系。我的分析思路為:

1、提出問(wèn)題——我的click事件的源碼到哪里去了呢?從編譯器代碼我們可以看到,前面的7句代碼都是對(duì)某個(gè)類(lèi)進(jìn)行賦值的操作,最真正起作用的就是最后Start方法的調(diào)用。這里又產(chǎn)生了幾個(gè)疑問(wèn)——d__0是什么類(lèi)型? 該類(lèi)型中的<>t__builder字段類(lèi)型的Start方法到底是做什么用的? 有了這兩個(gè)疑問(wèn),我們就點(diǎn)擊d__0(反射工具可以讓我們直接點(diǎn)擊查看)來(lái)看看它是什么類(lèi)型

#p#

 
 
 
 
  1. // d__0類(lèi)型的定義,從下面代碼可以看出它是一個(gè)結(jié)構(gòu)體
  2. // 該類(lèi)型是編譯器生成的一個(gè)嵌入類(lèi)型
  3. // 看到該類(lèi)型的實(shí)現(xiàn)有沒(méi)有讓你聯(lián)想到什么?
  4. private struct d__0 : IAsyncStateMachine
  5. {
  6.     // Fields
  7.     public int <>1__state;
  8.     public Form1 <>4__this;
  9.     public AsyncVoidMethodBuilder <>t__builder;
  10.     private object <>t__stack;
  11.     private TaskAwaiter <>u__$awaiter2;
  12.     public long 5__1;
  13.     public EventArgs e;
  14.     public object sender;
  15.     // Methods
  16.     private void MoveNext()
  17.     {
  18.         try
  19.         {
  20.             TaskAwaiter CS$0$0001;
  21.             bool <>t__doFinallyBodies = true;
  22.             switch (this.<>1__state)
  23.             {
  24.                 case -3:
  25.                     goto Label_010E;
  26.                 case 0:
  27.                     break;
  28.                 default:
  29.             // 獲取用于等待Task(任務(wù))的等待者。你要知道某個(gè)任務(wù)是否完成,我們就需要一個(gè)等待者對(duì)象對(duì)該任務(wù)進(jìn)行一個(gè)監(jiān)控,所以微軟就定義了一個(gè)等待者對(duì)象的
  30.             // 從這里可以看出,其實(shí)async和await關(guān)鍵字背后的實(shí)現(xiàn)原理是基于任務(wù)的異步編程模式(TAP)
  31.                     // 這里代碼是在線(xiàn)程池線(xiàn)程上運(yùn)行的
  32.                     CS$0$0001 = this.<>4__this.AccessWebAsync().GetAwaiter();
  33.             // 如果任務(wù)完成就調(diào)轉(zhuǎn)到Label_007A部分的代碼
  34.                     if (CS$0$0001.IsCompleted)
  35.                     {
  36.                         goto Label_007A;
  37.                     }
  38.            
  39.                     // 設(shè)置狀態(tài)為0為了退出回調(diào)方法。
  40.                     this.<>1__state = 0;
  41.                     this.<>u__$awaiter2 = CS$0$0001;
  42.             // 這個(gè)代碼是做什么用的呢?讓我們帶著問(wèn)題看下面的分析
  43. this.<>t__builder.AwaitUnsafeOnCompleted, Form1.d__0>(ref CS$0$0001, ref this);
  44.                     <>t__doFinallyBodies = false;
  45.             // 返回到調(diào)用線(xiàn)程,即GUI線(xiàn)程,這也是該方法不會(huì)堵塞GUI線(xiàn)程的原因,不管任務(wù)是否完成都返回到GUI線(xiàn)程
  46.                     return;
  47.             }
  48.             // 當(dāng)任務(wù)完成時(shí),不會(huì)執(zhí)行下面的代碼,會(huì)直接執(zhí)行Label_007A中代碼
  49.             CS$0$0001 = this.<>u__$awaiter2;
  50.             this.<>u__$awaiter2 = new TaskAwaiter();
  51.             // 為了使再次回調(diào)MoveNext代碼
  52.             this.<>1__state = -1;
  53.         Label_007A:
  54.             // 下面代碼是在GUI線(xiàn)程上執(zhí)行的
  55.             CS$0$0001 = new TaskAwaiter();
  56.             long CS$0$0003 = CS$0$0001.GetResult();
  57.             this.5__1 = CS$0$0003;
  58.         // 我們?cè)创a中的代碼這里的
  59.             this.<>4__this.OtherWork();
  60.             this.<>4__this.richTextBox1.Text = this.<>4__this.richTextBox1.Text + string.Format("\n 回復(fù)的字節(jié)長(zhǎng)度為:  {0}.\r\n", this.5__1);
  61.             this.<>4__this.txbMainThreadID.Text = Thread.CurrentThread.ManagedThreadId.ToString();
  62.         }
  63.         catch (Exception <>t__ex)
  64.         {
  65.             this.<>1__state = -2;
  66.             this.<>t__builder.SetException(<>t__ex);
  67.             return;
  68.         }
  69.     Label_010E:
  70.         this.<>1__state = -2;
  71.         this.<>t__builder.SetResult();
  72.     }
  73.     [DebuggerHidden]
  74.     private void SetStateMachine(IAsyncStateMachine param0)
  75.     {
  76.         this.<>t__builder.SetStateMachine(param0);
  77.     }
  78. }

如果你看過(guò)我的迭代器專(zhuān)題的話(huà),相信你肯定可以聯(lián)想到該結(jié)構(gòu)體就是一個(gè)迭代器的一個(gè)實(shí)現(xiàn),其主要方法就是MoveNext方法。從上面的代碼的注釋?xiě)?yīng)該可以幫助我們解決在第一步提到的第一個(gè)問(wèn)題,即d__0是什么類(lèi)型,下面就分析下第二個(gè)問(wèn)題,從d__0結(jié)構(gòu)體的代碼中可以發(fā)現(xiàn)<>t__builder的類(lèi)型是AsyncVoidMethodBuilder類(lèi)型,下面就看看它的Start方法的解釋——運(yùn)行關(guān)聯(lián)狀態(tài)機(jī)的生成器,即調(diào)用該方法就可以開(kāi)始運(yùn)行狀態(tài)機(jī),運(yùn)行狀態(tài)機(jī)指的就是執(zhí)行MoveNext方法(MoveNext方法中有我們?cè)创a中所有代碼,這樣就把編譯器生成的Click方法與我們的源碼關(guān)聯(lián)起來(lái)了)。從上面代碼注釋中可以發(fā)現(xiàn),當(dāng)該MoveNext被調(diào)用時(shí)會(huì)立即還回到 GUI線(xiàn)程中,同時(shí)也有這樣的疑問(wèn)——?jiǎng)傞_(kāi)始調(diào)用MoveNext方法時(shí),任務(wù)肯定是還沒(méi)有被完成的,但是我們輸出我們?cè)创a中的代碼,必須等待任務(wù)完成(因?yàn)槿蝿?wù)完成才能調(diào)轉(zhuǎn)到Label_007A中的代碼),此時(shí)我們應(yīng)該需要回調(diào)MoveNext方法來(lái)檢查任務(wù)是否完成,(就如迭代器中的,我們需要使用foreach語(yǔ)句一直調(diào)用MoveNext方法),然而我們?cè)诖a卻沒(méi)有找到回調(diào)的任何代碼??? 對(duì)于這個(gè)疑問(wèn),回調(diào)MoveNext方法肯定是存在的,只是首次看上面代碼的朋友還沒(méi)有找到類(lèi)似的語(yǔ)句而已,上面代碼注釋中我提到了一個(gè)問(wèn)題——這個(gè)代碼是做什么用的呢?讓我們帶著問(wèn)題看下面的分析,其實(shí)注釋下面的代碼就是起到回調(diào)MoveNext方法的作用,AsyncVoidMethodBuilder.AwaitUnsafeOnCompleted 方法就是調(diào)度狀態(tài)機(jī)去執(zhí)行MoveNext方法,從而也就解決了回調(diào)MoveNext的疑問(wèn)了。

相信大家從上面的解釋中可以找到源碼與編譯器代碼之間的對(duì)應(yīng)關(guān)系了吧, 但是我在分析完上面的之后,又有一個(gè)疑問(wèn)——當(dāng)任務(wù)完成時(shí),是如何退出MoveNext方法的呢?總不能讓其一直回調(diào)吧,從上面的代碼的注釋可以看出,當(dāng)任務(wù)執(zhí)行完成之后,會(huì)把<>1__state設(shè)置為0,當(dāng)下次再回調(diào)MoveNext方法時(shí)就會(huì)直接退出方法,然而任務(wù)沒(méi)完成之前,同樣也會(huì)把<>1__state設(shè)置為0,但是Switch部分后面的代碼又把<>1__state設(shè)置為-1,這樣就保證了在任務(wù)沒(méi)完成之前,MoveNext方法可以被重復(fù)回調(diào),當(dāng)任務(wù)完成之后,<>1__state設(shè)置為-1的代碼將不會(huì)執(zhí)行,而是調(diào)轉(zhuǎn)到 Label_007A部分。

經(jīng)過(guò)上面的分析之后,相信大家也可以耍出一套還我漂漂拳去分析異步方法AccessWebAsync(),其分析思路是和btnClick_Click的分析思路是一樣的.這里就不重復(fù)啰嗦了。

分析完之后,下面再分享下幾個(gè)關(guān)于async和await常問(wèn)的問(wèn)題

問(wèn)題一:是不是寫(xiě)了async關(guān)鍵字的方法就代表該方法是異步方法,不會(huì)堵塞線(xiàn)程呢?

答: 不是的,對(duì)于只標(biāo)識(shí)async關(guān)鍵字的(指在方法內(nèi)沒(méi)有出現(xiàn)await關(guān)鍵字)的方法,調(diào)用線(xiàn)程會(huì)把該方法當(dāng)成同步方法一樣執(zhí)行,所以然而會(huì)堵塞GUI線(xiàn)程,只有當(dāng)async和await光劍子同時(shí)出現(xiàn),該方法才被轉(zhuǎn)換為異步方法處理。

問(wèn)題二:“async”關(guān)鍵字會(huì)導(dǎo)致調(diào)用方法用線(xiàn)程池線(xiàn)程運(yùn)行嗎?

答: 不會(huì),被async關(guān)鍵字標(biāo)識(shí)的方法不會(huì)影響方法是同步還是異步運(yùn)行并完成,而是,它使方法可被分割成多個(gè)片段,其中一些片段可能異步運(yùn)行,這樣這個(gè)方法可能異步完成。這些片段界限就出現(xiàn)在方法內(nèi)部顯示使用”await”關(guān)鍵字的位置處。所以,如果在標(biāo)記了”async”的方法中沒(méi)有顯示使用”await”,那么該方法只有一個(gè)片段,并且將以同步方式運(yùn)行并完成。在await關(guān)鍵字出現(xiàn)的前面部分代碼和后面部分代碼都是同步執(zhí)行的(即在調(diào)用線(xiàn)程上執(zhí)行的,也就是GUI線(xiàn)程,所以不存在跨線(xiàn)程訪(fǎng)問(wèn)控件的問(wèn)題),await關(guān)鍵處的代碼片段是在線(xiàn)程池線(xiàn)程上執(zhí)行。總結(jié)為——使用async和 await關(guān)鍵字實(shí)現(xiàn)的異步方法,此時(shí)的異步方法被分成了多個(gè)代碼片段去執(zhí)行的,而不是像之前的異步編程模型(APM)和EAP那樣,使用線(xiàn)程池線(xiàn)程去執(zhí)行一整個(gè)方法。

關(guān)于更多async和await關(guān)鍵字的常問(wèn)問(wèn)題可以查看——Async/Await FAQ和中文翻譯——(譯)關(guān)于async與await的FAQ

六、小結(jié)

寫(xiě)到這里本專(zhuān)題的內(nèi)容就介紹到這里的,并且我也會(huì)把本專(zhuān)題的內(nèi)容同步到之前的C#基礎(chǔ)知識(shí)系列文章索引,這樣我的C#特性系列也就完整了,并且該專(zhuān)題也是異步編程的最后一篇專(zhuān)題,在后面的專(zhuān)題將為大家實(shí)現(xiàn)一個(gè)類(lèi)似迅雷的多任務(wù)多線(xiàn)程下載器,對(duì)于這個(gè)專(zhuān)題可能會(huì)用到并行編程的內(nèi)容,所以接下面我為為大家分享下并行編程的內(nèi)容。

本專(zhuān)題所有源碼下載:ASyncAndAwaitTestProject.zip


分享名稱(chēng):C#5.0新特性:Async和Await使異步編程更簡(jiǎn)單
網(wǎng)站地址:http://www.dlmjj.cn/article/djdhide.html