




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第C#使用async和await實現(xiàn)異步編程最近在寫程序的時候,經(jīng)常遇到大量需要異步訪問的情況,但是對于async和await到底怎么寫,還不是非常明確。
1.普通的程序怎么寫?
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
從運行結(jié)果可以看到,同步執(zhí)行的時間主要花在了兩次請求外部地址上,計算長度并不費時,用圖來表示就像下面
2.使用async和await怎么寫?
修改上面代碼,如下
classMyDownLoadString
Stopwatchsw=newStopwatch();
publicvoidDoRun()
constintLargeNumber=6000000;
sw.Start();
//Taskint保存結(jié)果對象,后面t1.Result則是獲取結(jié)果
Taskintt1=CountCharactersAsync(1,"");
Taskintt2=CountCharactersAsync(2,"");
//無需等待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);
}
運行結(jié)果:
Call1start:2ms
Call2start:253ms
EndCountToALargeNumber1:288ms
EndCountToALargeNumber2:359ms
EndCountToALargeNumber3:560ms
Call1completed:770ms
EndCountToALargeNumber4:844ms
Call2completed:887ms
CharsinCall1:162262
CharsinCall2:5164
修改如上面的代碼之后,我們就可以無需等待兩次CountCharactersAsync返回結(jié)果,而是直接調(diào)用了下面的CountToALargeNumber,在CountCharactersAsync請求返回的時候再獲取結(jié)果。
3.async和await的細節(jié)
async和await可以創(chuàng)建和使用異步方法,這個特性的由三個部分組成:
①調(diào)用方法(callingmethod):該方法調(diào)用異步方法,然后在異步方法(可能使用同一個線程也可能不在一個線程)執(zhí)行其任務(wù)的時候繼續(xù)執(zhí)行②異步方法(async):該方法異步執(zhí)行其工作,然后立即方法到調(diào)用方法③await表達式:用于異步方法內(nèi)部,指明需要異步執(zhí)行的惹怒我。一個異步方法可以包含任意多個await表達式,如果一個都不包含編譯器會發(fā)出警告
舉例說明一個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表達式
intsum=awaitTask.Run(()={returna+b;});
returnsum;
}
4.什么是異步方法?
上面簡單舉例了什么是異步方法,下面就詳細學習一下:
異步方法在完成其工作之前返回到調(diào)用方法,并在調(diào)用方法繼續(xù)執(zhí)行的時候完成其工作。語法上有如下特征:
①方法使用async作為修飾符②方法內(nèi)部包含一個或者多個await表達式,表示可以異步完成的任務(wù)③必須具備以下三種返回類型void、Task、TaskT,其中后兩種的返回對象標識講座未來完成的工作,調(diào)用方法和異步方法可以繼續(xù)執(zhí)行。④異步方法的參數(shù)可以任意類型,但是不能為out和ref參數(shù)⑤約定俗成,一般異步方法都是以Async作為后綴的。⑥除了方法之外,Lambda表達式和匿名函數(shù)也可以作為異步對象。
像代碼:
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;
}
詳細說明:
①async關(guān)鍵字是一個上下文關(guān)鍵字,也就是說除了做為方法(lambda和匿名函數(shù))的修飾符之外,還可以做標識符。
②返回類型
Task類型:如果調(diào)用方法不需要從異步方法中返回某個值,但需要檢查異步方法的狀態(tài),可以返回一個Task,此時就算異步方法中出現(xiàn)了return語句,也不會返回任何東西。TaskT類型,除了上面Task的功能,還可以通過Return屬性來獲取返回的T類型的值。void類型:如果僅僅是執(zhí)行異步方法,而不需要與它做任何進一步的交互(調(diào)用并忘記),此時可以用void,和Task一樣,就算有return語句,也得不到任何東西。
5.異步方法的控制流
首先要明確異步方法的三個部分,如下圖所示:
①首先是第一個await之前的部分,這部分應(yīng)該是少量且無需長時間等待的代碼。②await表達式,表示需要被異步執(zhí)行的任務(wù),這里有兩個await表達式,第二個await和之前的同步部分和第一個await以及之前的部分是一樣的。③后續(xù)部分:在await表達式之后出現(xiàn)的方法中的其余代碼。
執(zhí)行過程,可以參考下面的圖
有幾個注意的地方:
①await之前的部分是同步執(zhí)行的②當達到awati的時候,會將異步方法的控制返回給調(diào)用方法。如果方法返回的類型是Task或者TaskT,將創(chuàng)建一個Task對象,表示需異步完成的任務(wù)和后續(xù),然后將該Task返回到調(diào)用方法。這里的返回值并不是await表達式的返回值,而是異步方法中聲明的返回值類型。③異步方法內(nèi)部需要完成以下工作:
-異步執(zhí)行await表達是的空閑任務(wù)
-當await表達式執(zhí)行完成之后,執(zhí)行后續(xù)部分。后續(xù)本身也可能是await表達式,處理過程和上一個一致。
-后續(xù)部分如果遇到return或者方法達到末尾,將做如下的事情:
l如果返回的類型是void,控制流就退出了
l如果返回的類型是Task,后續(xù)部分設(shè)置Task對象的屬性并退出。
l如果返回的類型是TaskT,不僅要設(shè)置Task對象屬性,還要設(shè)置Task對象的Return屬性。
這個點要注意下:并不是遇到return或者達到方法末尾,就能獲取到返回值,它只是退出了。
④調(diào)用方法繼續(xù)執(zhí)行,會從異步方法獲取Task對象。當需要其實際值的時候,就引用Task對象中的Result屬性。屆時,如果異步方法設(shè)置了該屬性,調(diào)用方法獲取其值并繼續(xù)。否則就等待該屬性被設(shè)置,然后再繼續(xù)執(zhí)行。
6.await表達式
await表達式指定了一個異步執(zhí)行的任務(wù)。語法由await關(guān)鍵字+一個空閑對象(稱為任務(wù))組成。這個任務(wù)可能是一個Task對象,也可以不是,默認情況下由該線程異步執(zhí)行。
一個空閑對象指的是一個awaitable類型的實例,awaitable類型是指包含了GetAwaiter方法的類型,方法沒有參數(shù),返回一個稱為awaiter類型的對象。
一個awaiter對象包含了如下成員:
一般情況下我們不需要自己構(gòu)建一個awaiter對象,使用.net自己的Task就可以了。最簡單的方法就是使用Task.Run()來返回一個Task對象。關(guān)于Task.Run()有一個非常重要的點,他將在不同的線程上運行你的方法。
6.異常處理和await表達式
先看下面這個例子,直接在異步方法內(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)部進行了try..catch,并且也catch到了異常,但是對于調(diào)用函數(shù),返回的Task狀態(tài)依然為RanToCompletion。
為什么這個亞子?,原因如下:
①Task沒有被取消掉②沒有未處理的異常。類似的IsFaulted是false。
7.在調(diào)用方法中同步的等待任務(wù)(WaitAll、WaitAny)
對于單個Task,可以通過task對象的wait()方法來進行等待。
Taskintt=CountCharactersAsync("");
t.Wait();
對于多個Task,可以使用WaitAll()或者waitAny()方法,進行同步。
WaitAll是等待所以的任務(wù)完成才繼續(xù)操作
Taskintt1=CountCharactersAsync(1,"");
Taskintt2=CountCharactersAsync(2,"");
Taskint[]tasks=newTaskint[]{t1,t2};
Task.WaitAll(tasks);
WaitAny是只要一個完成就可以繼續(xù)操作
Taskintt1=CountCharactersAsync(1,"");
Taskintt2=CountCharactersAsync(2,"");
Taskint[]tasks=newTaskint[]{t1,t2};
Task.WaitAny(tasks);
8.在異步方法中異步的等待任務(wù)(WhenAll、.WhenAny)
上面說明了如何在調(diào)用方法中,同步等待Task的完成。但是有時候,我們在一個異步方法中也會存在多個任務(wù),想要讓它們通過await表達式等待。我們可以通過Task.WhenAll()和Task.WhenAny()方法實現(xiàn)。這兩個方法稱為組合子(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. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年衛(wèi)生資格(中初級)-中醫(yī)婦科學主治醫(yī)師歷年參考題庫含答案解析(5套典型題)
- 2025年醫(yī)藥衛(wèi)生考試-等級醫(yī)院評審知識考試歷年參考題庫含答案解析(5套典型題)
- 2025年醫(yī)學高級職稱-臨床醫(yī)學檢驗臨床免疫技術(shù)(醫(yī)學高級)歷年參考題庫含答案解析(5套典型題)
- 2025年會計職稱考試-社保帳戶管理兼基金會計崗位考試歷年參考題庫含答案解析(5套典型考題)
- 2025年專業(yè)技術(shù)人員繼續(xù)教育公需科目-信息技術(shù)與信息安全歷年參考題庫含答案解析(5套典型考題)
- 2023-2025年高考語文試題分類匯編:作文解析版
- 企業(yè)承接協(xié)議書
- 親子旅游協(xié)議書
- 亞馬遜股東協(xié)議書
- 乙方通訊協(xié)議書
- 特種設(shè)備安全管理-使用知識
- 難治性高血壓的治療策略
- 肝臟腫瘤的影像診斷及鑒別診斷講座演示文稿
- H35-462(5G中級)認證考試題庫(附答案)
- 2023年全科醫(yī)師轉(zhuǎn)崗培訓理論考試試題及答案
- GB/T 17642-1998土工合成材料非織造復合土工膜
- 3C認證全套體系文件(手冊+程序文件)
- 魚類繁殖與發(fā)育課件
- (完整)五金材料采購清單
- 政企業(yè)務(wù)認知題庫V1
- 制造執(zhí)行系統(tǒng)的功能與實踐最新ppt課件(完整版)
評論
0/150
提交評論