參考網址:https://www.cnblogs.com/zhurunlai/p/9714320.html
1.前言
*.NET Framework提供了執行異步操作的三種模式:
異步程式設計模型(APM)模式(也稱為IAsyncResult的模式),其中異步操作要求Begin和End方法(例如,BeginWrite和EndWrite異步寫入操作)。這種模式不再被推薦用于新開發。有關更多資訊,請參閱異步程式設計模型(APM)。
基于事件的異步模式(EAP),它需要一個具有Async字尾的方法,并且還需要一個或多個事件,事件處理程式委托類型和被EventArg派生類型。EAP在.NET Framework 2.0中引入。不再推薦新的開發。有關更多資訊,請參閱基于事件的異步模式(EAP)。
基于任務的異步模式(TAP),它使用單一方法來表示異步操作的啟動和完成。TAP在.NET Framework 4中引入,是.NET Framework中推薦的異步程式設計方法。C#中的async和等待關鍵字,Visual Basic語言中的Async和Await運算符為TAP添加語言支援。有關更多資訊,請參閱基于任務的異步模式(TAP)。*
2.異步的應用場景
在計算機程式的運作中,計算是需要一定的時間的,在運算時間過長的任務時,比如上傳大檔案、讀取檔案流、資料庫操作、httprequest等,如果是同步(synvronous)必須等待該任務執行完成才能繼續下一個任務。使用異步(asynchronous)操作,會開啟新的線程,不會等待異步操作完成才去執行後面的程式,相比異步程式設計優點:1.就是出現長時間處理程式時,不會卡界面,使用者仍然可以操作UI界面2.提高程式運作效率,節約CPU資源,提供系統吞吐量。
3.程序和線程的關系
這個面試的時候基本上都會問到,簡而言之就是:
一個程式都會有一個程序和一個線程,程序是由CPU進行排程配置設定資源的,有一個完整的虛拟位址空間,不依賴線程獨立存在,反之線程是由程序來排程配置設定的,隻是程序的一部分,沒有自己的位址空間,與程序内的其他線程一起共享該程序的所有資源。打個簡單的比方就像是線程就好比是人體的寄生蟲,不能獨立存在,必須依靠人(程序)的營養(資源)來生存(執行)
4.異步和多線程的差別
異步是相對同步而言的,我們知道異步是開啟了新線程,但是和多線程不是一個概念,異步相當于一個人的“大腦”能夠做試卷,又能夠看電影,同時處理兩件以上不同的事情。多線程好比多個人做不同的事情。
異步操作的本質
c#中異步和多線程的差別是什麼呢?異步和多線程兩者都可以達到避免調用線程阻塞的目的,進而提高軟體的可響應性。 所有的程式最終都會由計算機硬體來執行,無須消耗CPU時間的I/O操作正是異步操作的硬體基礎。
線程的本質
線程不是一個計算機硬體的功能,而是作業系統提供的一種邏輯功能,線程本質上是程序中一段并發運作的代碼,是以線程需要作業系統投入CPU資源來運作和排程
異步操作的優缺點
因為異步操作無須額外的線程負擔,并且使用回調的方式進行處理,在設計良好的情況下,處理函數可以不必使用共享變量(即使無法完全不用,最起碼可以減少 共享變量的數量),減少了死鎖的可能。當然異步操作也并非完美無暇。編寫異步操作的複雜程度較高,程式主要使用回調方式進行處理,與普通人的思維方式有些出入,而且難以調試。
多線程的優缺點
多線程的優點很明顯,線程中的處理程式依然是順序執行,符合普通人的思維習慣,是以程式設計簡單。但是多線程的缺點也同樣明顯,線程的使用(濫用)會給系統帶來上下文切換的額外負擔。并且線程間的共享變量可能造成死鎖的出現。
适用範圍
當需要執行I/O操作時,使用異步操作比使用線程+同步 I/O操作更合适。I/O操作不僅包括了直接的檔案、網絡的讀寫,還包括資料庫操作、Web Service、HttpRequest以及.net Remoting等跨程序的調用。
而線程的适用範圍則是那種需要長時間CPU運算的場合,例如耗時較長的圖形處理和算法執行。但是往往由于使用線程程式設計的簡單和符合習慣,是以很多朋友往往會使用線程來執行耗時較長的I/O操作。這樣在隻有少數幾個并發操作的時候還無傷大雅,如果需要處理大量的并發操作時就不合适了。
5.C#異步方式之一( BeginInvoke、EndInvoke方法)
方式1:使用回調方法完成異步委托
先來看個例子,委托的異步調用,這個例子首先定義一個string類型的傳回值、string類型的參數的委托。雖然這中模式不推薦被使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
前兩種調用委托的方式都是同步的,BeginInvoke方法的傳回值是IAsyncResult類型的
該方法的參數由兩部分組成,前面(n)個參數是委托的參數,倒數第二個參數也表示一個委托,該委托是.net系統定義的委托(和func、action類似),檢視AsyncCallback的定義如圖:
作用就是:作為執行調用的回調方法,值得注意的是,在回調方法中,必須調用EndInvoke方法結束異步調用,EndInvoke是擷取異步調用的結果
上面的例子調試的結果如圖:
方式2:使用輪詢
我們把BeginInvoke的委托參數為null,使用輪詢的方式
|
結果如圖:
6.C#異步方式之二 await async
async和await是一對關鍵字,它是.net 4.5的特性。在實際工作中使用友善靈活,主要原因就是可以像寫同步方法那樣去異步程式設計,代碼結構清晰,不用關心如何實作異步的程式設計。
這裡其實要注意的是,之前剛說了異步是開啟新的線程來實作的,但是await 和async兩個關鍵字并沒有開啟新的線程,為了證明這一點,下面建了一個winform的程式,異步擷取圖檔并顯示到picturebox上。
|
其實不用看圖就已經知道答案了,程式運作時不報異常,就已經說明一點:await async兩個關鍵根本建立新的線程。這個涉及到異步更新UI到主線程,就不多說了。
結果如圖:
async await方法的使用說明:
- 傳回類型: void 、Task、Task<泛型類型>
- async、await不會建立新的線程,實作等待的效果,必須同時使用
- 使用該方法的方法主體也要用async關鍵字
異步方法事例:
|
調用異步方法:
|
7.C#異步方式之三 淺談Task
前面剛剛了解到async await是.net 4.5出的特性,Task是.net4.0新出的特性,用來處理異步程式設計的,其實我們要知道真正實作的異步操作還是Task新增線程來實作的,但是不代表說開一個Task,就開一個線程,有可能是幾個Task在一個線程上運作的,他們并不是一一對應的關系,充分利用線程,下面的事例就已經能夠說明這一點
Task建立
Task建立有兩種方式一種通過任務工廠指派立即運作,一種是直接執行個體化。下面這個例子建立了10個Task
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | |
建立的10個Task,我們從結果中也證明了Task和線程并不是一一對應的關系,結果如圖:
Task構造函數
Task狀态
我們建立一個task,調用他的Start、Wait方法
|
我們從圖中可以知道,Task的生命周期如下:
Created:在已經執行個體化未Start之前的狀态
WaittingToRun:表示等待配置設定線程給Task執行
RanToCompletion:任務執行完畢
Task等待任務結果
1.Task.WaitAll從這個字面意思就知道等待所有任務執行完成,和上面例子Wait方法等待一個任務執行完成很相似,我們來看一個代碼:
|
結果輸出:
task1Created
task2Created
所有任務執行完
除了WaitAll方法還有這些常用的方法
- Task.WaitAny:等待任何一個任務向下執行
- Task.ContinueWith等待第一個Task完成自動啟動,觸發下一個Task,也就是當做任務完成時觸發的回調方法
- Task.GetAwaiter().OnCompleted(Action action) :GetAwaiter 方法擷取任務的等待者,調用OnCompleted事件,任務完成時觸發
Task任務取消
|