




版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第C#使用async和await實(shí)現(xiàn)異步編程最近在寫(xiě)程序的時(shí)候,經(jīng)常遇到大量需要異步訪(fǎng)問(wèn)的情況,但是對(duì)于async和await到底怎么寫(xiě),還不是非常明確。
1.普通的程序怎么寫(xiě)?
classProgram
staticvoidMain(string[]args)
MyDownLoadStringds=newMyDownLoadString();
ds.DoRun();
Console.ReadKey();
classMyDownLoadString
Stopwatchsw=newStopwatch();
publicvoidDoRun()
constintLargeNumber=6000000;
sw.Start();
intt1=CountCharacters(1,"");
intt2=CountCharacters(2,"");
CountToALargeNumber(1,LargeNumber);
CountToALargeNumber(2,LargeNumber);
CountToALargeNumber(3,LargeNumber);
CountToALargeNumber(4,LargeNumber);
Console.WriteLine("CharsinCall1:{0}",t1);
Console.WriteLine("CharsinCall1:{0}",t2);
privateintCountCharacters(intid,stringuriString)
WebClientwc1=newWebClient();
Console.WriteLine("Call{0}start:{1:N0}ms",id,sw.Elapsed.TotalMilliseconds);
stringresult=wc1.DownloadString(newUri(uriString));
Console.WriteLine("Call{0}completed:{1:N0}ms",id,sw.Elapsed.TotalMilliseconds);
returnresult.Length;
privatevoidCountToALargeNumber(intid,intvalue)
for(longi=0;ivalue;i++);
Console.WriteLine("EndCountToALargeNumber{0}:{1:N0}ms",id,sw.Elapsed.TotalMilliseconds);
}
結(jié)果:
Call1start:1ms
Call1completed:903ms
Call2start:903ms
Call2completed:1,355ms
EndCountToALargeNumber1:1,375ms
EndCountToALargeNumber2:1,399ms
EndCountToALargeNumber3:1,417ms
EndCountToALargeNumber4:1,435ms
CharsinCall1:161702
CharsinCall1:5164
從運(yùn)行結(jié)果可以看到,同步執(zhí)行的時(shí)間主要花在了兩次請(qǐng)求外部地址上,計(jì)算長(zhǎng)度并不費(fèi)時(shí),用圖來(lái)表示就像下面
2.使用async和await怎么寫(xiě)?
修改上面代碼,如下
classMyDownLoadString
Stopwatchsw=newStopwatch();
publicvoidDoRun()
constintLargeNumber=6000000;
sw.Start();
//Taskint保存結(jié)果對(duì)象,后面t1.Result則是獲取結(jié)果
Taskintt1=CountCharactersAsync(1,"");
Taskintt2=CountCharactersAsync(2,"");
//無(wú)需等待CountCharactersAsync執(zhí)行完成
CountToALargeNumber(1,LargeNumber);
CountToALargeNumber(2,LargeNumber);
CountToALargeNumber(3,LargeNumber);
CountToALargeNumber(4,LargeNumber);
//t1.Result獲取結(jié)果
Console.WriteLine("CharsinCall1:{0}",t1.Result);
Console.WriteLine("CharsinCall1:{0}",t2.Result);
privateasyncTaskintCountCharactersAsync(intid,stringuriString)
WebClientwc=newWebClient();
Console.WriteLine("Call{0}start:{1:N0}ms",id,sw.Elapsed.TotalMilliseconds);
stringresult=awaitwc.DownloadStringTaskAsync(newUri(uriString));
Trace.TraceInformation("TaceingAsyncCall{0}@time:{1:N0}ms",id,sw.Elapsed.TotalMilliseconds);
Console.WriteLine("Call{0}completed:{1:N0}ms",id,sw.Elapsed.TotalMilliseconds);
returnresult.Length;
privatevoidCountToALargeNumber(intid,intvalue)
for(longi=0;ivalue;i++);
Console.WriteLine("EndCountToALargeNumber{0}:{1:N0}ms",id,sw.Elapsed.TotalMilliseconds);
}
運(yùn)行結(jié)果:
Call1start:2ms
Call2start:253ms
EndCountToALargeNumber1:288ms
EndCountToALargeNumber2:359ms
EndCountToALargeNumber3:560ms
Call1completed:770ms
EndCountToALargeNumber4:844ms
Call2completed:887ms
CharsinCall1:162262
CharsinCall2:5164
修改如上面的代碼之后,我們就可以無(wú)需等待兩次CountCharactersAsync返回結(jié)果,而是直接調(diào)用了下面的CountToALargeNumber,在CountCharactersAsync請(qǐng)求返回的時(shí)候再獲取結(jié)果。
3.async和await的細(xì)節(jié)
async和await可以創(chuàng)建和使用異步方法,這個(gè)特性的由三個(gè)部分組成:
①調(diào)用方法(callingmethod):該方法調(diào)用異步方法,然后在異步方法(可能使用同一個(gè)線(xiàn)程也可能不在一個(gè)線(xiàn)程)執(zhí)行其任務(wù)的時(shí)候繼續(xù)執(zhí)行②異步方法(async):該方法異步執(zhí)行其工作,然后立即方法到調(diào)用方法③await表達(dá)式:用于異步方法內(nèi)部,指明需要異步執(zhí)行的惹怒我。一個(gè)異步方法可以包含任意多個(gè)await表達(dá)式,如果一個(gè)都不包含編譯器會(huì)發(fā)出警告
舉例說(shuō)明一個(gè)async/await方法:
//1.調(diào)用方法
staticvoidMain(string[]args)
Taskintt=DoSumAsync(1,2);
Console.WriteLine("結(jié)果:{0}",t.Result);
Console.ReadKey();
//2.異步方法
publicstaticasyncTaskintDoSumAsync(inta,intb)
//3.await表達(dá)式
intsum=awaitTask.Run(()={returna+b;});
returnsum;
}
4.什么是異步方法?
上面簡(jiǎn)單舉例了什么是異步方法,下面就詳細(xì)學(xué)習(xí)一下:
異步方法在完成其工作之前返回到調(diào)用方法,并在調(diào)用方法繼續(xù)執(zhí)行的時(shí)候完成其工作。語(yǔ)法上有如下特征:
①方法使用async作為修飾符②方法內(nèi)部包含一個(gè)或者多個(gè)await表達(dá)式,表示可以異步完成的任務(wù)③必須具備以下三種返回類(lèi)型void、Task、TaskT,其中后兩種的返回對(duì)象標(biāo)識(shí)講座未來(lái)完成的工作,調(diào)用方法和異步方法可以繼續(xù)執(zhí)行。④異步方法的參數(shù)可以任意類(lèi)型,但是不能為out和ref參數(shù)⑤約定俗成,一般異步方法都是以Async作為后綴的。⑥除了方法之外,Lambda表達(dá)式和匿名函數(shù)也可以作為異步對(duì)象。
像代碼:
privateasyncTaskintCountCharactersAsync(intid,stringuriString)
WebClientwc=newWebClient();
Console.WriteLine("Call{0}start:{1:N0}ms",id,sw.Elapsed.TotalMilliseconds);
stringresult=awaitwc.DownloadStringTaskAsync(newUri(uriString));
Trace.TraceInformation("TaceingAsyncCall{0}@time:{1:N0}ms",id,sw.Elapsed.TotalMilliseconds);
Console.WriteLine("Call{0}completed:{1:N0}ms",id,sw.Elapsed.TotalMilliseconds);
returnresult.Length;
}
詳細(xì)說(shuō)明:
①async關(guān)鍵字是一個(gè)上下文關(guān)鍵字,也就是說(shuō)除了做為方法(lambda和匿名函數(shù))的修飾符之外,還可以做標(biāo)識(shí)符。
②返回類(lèi)型
Task類(lèi)型:如果調(diào)用方法不需要從異步方法中返回某個(gè)值,但需要檢查異步方法的狀態(tài),可以返回一個(gè)Task,此時(shí)就算異步方法中出現(xiàn)了return語(yǔ)句,也不會(huì)返回任何東西。TaskT類(lèi)型,除了上面Task的功能,還可以通過(guò)Return屬性來(lái)獲取返回的T類(lèi)型的值。void類(lèi)型:如果僅僅是執(zhí)行異步方法,而不需要與它做任何進(jìn)一步的交互(調(diào)用并忘記),此時(shí)可以用void,和Task一樣,就算有return語(yǔ)句,也得不到任何東西。
5.異步方法的控制流
首先要明確異步方法的三個(gè)部分,如下圖所示:
①首先是第一個(gè)await之前的部分,這部分應(yīng)該是少量且無(wú)需長(zhǎng)時(shí)間等待的代碼。②await表達(dá)式,表示需要被異步執(zhí)行的任務(wù),這里有兩個(gè)await表達(dá)式,第二個(gè)await和之前的同步部分和第一個(gè)await以及之前的部分是一樣的。③后續(xù)部分:在await表達(dá)式之后出現(xiàn)的方法中的其余代碼。
執(zhí)行過(guò)程,可以參考下面的圖
有幾個(gè)注意的地方:
①await之前的部分是同步執(zhí)行的②當(dāng)達(dá)到awati的時(shí)候,會(huì)將異步方法的控制返回給調(diào)用方法。如果方法返回的類(lèi)型是Task或者TaskT,將創(chuàng)建一個(gè)Task對(duì)象,表示需異步完成的任務(wù)和后續(xù),然后將該Task返回到調(diào)用方法。這里的返回值并不是await表達(dá)式的返回值,而是異步方法中聲明的返回值類(lèi)型。③異步方法內(nèi)部需要完成以下工作:
-異步執(zhí)行await表達(dá)是的空閑任務(wù)
-當(dāng)await表達(dá)式執(zhí)行完成之后,執(zhí)行后續(xù)部分。后續(xù)本身也可能是await表達(dá)式,處理過(guò)程和上一個(gè)一致。
-后續(xù)部分如果遇到return或者方法達(dá)到末尾,將做如下的事情:
l如果返回的類(lèi)型是void,控制流就退出了
l如果返回的類(lèi)型是Task,后續(xù)部分設(shè)置Task對(duì)象的屬性并退出。
l如果返回的類(lèi)型是TaskT,不僅要設(shè)置Task對(duì)象屬性,還要設(shè)置Task對(duì)象的Return屬性。
這個(gè)點(diǎn)要注意下:并不是遇到return或者達(dá)到方法末尾,就能獲取到返回值,它只是退出了。
④調(diào)用方法繼續(xù)執(zhí)行,會(huì)從異步方法獲取Task對(duì)象。當(dāng)需要其實(shí)際值的時(shí)候,就引用Task對(duì)象中的Result屬性。屆時(shí),如果異步方法設(shè)置了該屬性,調(diào)用方法獲取其值并繼續(xù)。否則就等待該屬性被設(shè)置,然后再繼續(xù)執(zhí)行。
6.await表達(dá)式
await表達(dá)式指定了一個(gè)異步執(zhí)行的任務(wù)。語(yǔ)法由await關(guān)鍵字+一個(gè)空閑對(duì)象(稱(chēng)為任務(wù))組成。這個(gè)任務(wù)可能是一個(gè)Task對(duì)象,也可以不是,默認(rèn)情況下由該線(xiàn)程異步執(zhí)行。
一個(gè)空閑對(duì)象指的是一個(gè)awaitable類(lèi)型的實(shí)例,awaitable類(lèi)型是指包含了GetAwaiter方法的類(lèi)型,方法沒(méi)有參數(shù),返回一個(gè)稱(chēng)為awaiter類(lèi)型的對(duì)象。
一個(gè)awaiter對(duì)象包含了如下成員:
一般情況下我們不需要自己構(gòu)建一個(gè)awaiter對(duì)象,使用.net自己的Task就可以了。最簡(jiǎn)單的方法就是使用Task.Run()來(lái)返回一個(gè)Task對(duì)象。關(guān)于Task.Run()有一個(gè)非常重要的點(diǎn),他將在不同的線(xiàn)程上運(yùn)行你的方法。
6.異常處理和await表達(dá)式
先看下面這個(gè)例子,直接在異步方法內(nèi)部使用了try..catch。
staticvoidMain(string[]args)
Taskt=BadAsync();
t.Wait();
Console.WriteLine("TaskStatus:{0}",t.Status);
Console.WriteLine("TaskIsFaulted:{0}",t.IsFaulted);
Console.WriteLine("Pleaseenterakeytoexit!");
Console.ReadKey();
staticasyncTaskBadAsync()
awaitTask.Run(()={thrownewException();});
catch
Console.WriteLine("ExceptioninBadAsync");
}
執(zhí)行結(jié)果:
ExceptioninBadAsync
TaskStatus:RanToCompletion
TaskIsFaulted:False
Pleaseenterakeytoexit!
從結(jié)果可以看到,雖然在異步方法內(nèi)部進(jìn)行了try..catch,并且也catch到了異常,但是對(duì)于調(diào)用函數(shù),返回的Task狀態(tài)依然為RanToCompletion。
為什么這個(gè)亞子?,原因如下:
①Task沒(méi)有被取消掉②沒(méi)有未處理的異常。類(lèi)似的IsFaulted是false。
7.在調(diào)用方法中同步的等待任務(wù)(WaitAll、WaitAny)
對(duì)于單個(gè)Task,可以通過(guò)task對(duì)象的wait()方法來(lái)進(jìn)行等待。
Taskintt=CountCharactersAsync("");
t.Wait();
對(duì)于多個(gè)Task,可以使用WaitAll()或者waitAny()方法,進(jìn)行同步。
WaitAll是等待所以的任務(wù)完成才繼續(xù)操作
Taskintt1=CountCharactersAsync(1,"");
Taskintt2=CountCharactersAsync(2,"");
Taskint[]tasks=newTaskint[]{t1,t2};
Task.WaitAll(tasks);
WaitAny是只要一個(gè)完成就可以繼續(xù)操作
Taskintt1=CountCharactersAsync(1,"");
Taskintt2=CountCharactersAsync(2,"");
Taskint[]tasks=newTaskint[]{t1,t2};
Task.WaitAny(tasks);
8.在異步方法中異步的等待任務(wù)(WhenAll、.WhenAny)
上面說(shuō)明了如何在調(diào)用方法中,同步等待Task的完成。但是有時(shí)候,我們?cè)谝粋€(gè)異步方法中也會(huì)存在多個(gè)任務(wù),想要讓它們通過(guò)await表達(dá)式等待。我們可以通過(guò)Task.WhenAll()和Task.WhenAny()方法實(shí)現(xiàn)。這兩個(gè)方法稱(chēng)為組合子(combinator)。
privateasyncTaskintCountCharactersAsync(stringsite1,stringsite2)
WebClientwc1=newWebClient();
WebClientwc2=newWebClient();
Taskstringt1=wc1.DownloadStringTaskAsync(newUri(site1));
Taskstringt2=wc2.DownloadStringTaskAsync(newUri(site2));
ListTaskstringtasks=newListTaskstring();
tasks.Add(t1);
tasks
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 橙色可愛(ài)卡通節(jié)約糧食模板
- 股權(quán)轉(zhuǎn)讓協(xié)議
- 產(chǎn)品業(yè)務(wù)提成合同范例
- 人事部經(jīng)理工作總結(jié)模版
- 醫(yī)療健康大數(shù)據(jù)驅(qū)動(dòng)的個(gè)性化醫(yī)療解決方案
- 2025年小學(xué)體育教師年度考核個(gè)人工作總結(jié)模版
- 運(yùn)輸新質(zhì)生產(chǎn)力
- 預(yù)留、預(yù)埋、防雷等施工技術(shù)總結(jié)
- 中藥柜銷(xiāo)售合同范例
- 醫(yī)院科室質(zhì)控工作總結(jié)模版
- 8.3 法治社會(huì) 課件高中政治統(tǒng)編版必修三政治與法治
- 工程安全施工方案范本
- 《昨日重現(xiàn)》中英文歌詞對(duì)照
- DB13-T 5687-2023 負(fù)壓封閉引流術(shù)護(hù)理規(guī)范
- 北大A計(jì)劃在線(xiàn)測(cè)評(píng)題
- 微博運(yùn)營(yíng)方案及工作計(jì)劃
- 《體育精神》-體育故事與體育精神培養(yǎng)教案
- 部編本一年級(jí)下冊(cè)1、吃水不忘挖井人名師公開(kāi)課獲獎(jiǎng)?wù)n件百校聯(lián)賽一等獎(jiǎng)?wù)n件
- 投資合同:有限公司投資協(xié)議
- 四川大學(xué)華西口腔醫(yī)院臨床研究醫(yī)學(xué)倫理審查申請(qǐng)表【模板】
- 拖欠房租通知書(shū)范文
評(píng)論
0/150
提交評(píng)論