C#併發編程之異步編程(一)

寫在前面

C#5.0中,對異步編程進行了一次革命性的重構,引入了async和await這兩個關鍵字,使得開發人員在不須要深入瞭解異步編程的底層原理,就能夠寫出十分優美而又代碼量極少的代碼。若是使用得當,你能夠寫出具備並行化而且性能較高的程序,可是同時也增長了對異步編程理解的複雜度,畢竟在C#5.0裏,你已經看不到異步編程具體是如何實現的了,須要花費額外的經歷去研究探索。數據庫

使用異步編程,使得咱們釋放了啓動它的線程,也使得資源的佔有量降低。更重要的是,有些特殊線程,好比UI線程,在運行的時候只能啓動一個,若是沒有快速響應,頁面將會出現卡頓現象。本文只會基於.NET FX4.5及之後的版本進行講解,以前的版本若是要實現異步編程,須要從nuget上面下載Microsoft.Bcl.Async,不過我仍是建議你,若是想要在系統中大量使用編寫異步代碼,仍是要是使用.NET FX4.5或更高的版本編程

異步編程主要分爲基於事件的異步模式(EAP)和基於任務的編程模式(TAP)。EAP在調用方法以前當即註冊事件,它具備void返回類型,但這種模式比較混亂,它將本來的一個方法分拆成兩個方法。本系列主要關注TAP編程而不涉及EAP編程。異步

異步編程是什麼

異步關鍵字

做爲C#5.0中新增的重量級功能,異步功能是指程序在進行長時間操做完成後,須要繼續執行的操做的一種方法,在編程過程當中,會感受這些異步代碼和同步或者阻塞代碼相似,可是實際上,編譯器會將標識爲異步的方法進行進一步的轉換,是的代碼能夠實現真正的異步編程。它主要以兩個關鍵字的形式功能你們使用:async

  • async
  • await

如下以一個經過EF Core查詢用戶信息的代碼片斷,這個例子沒有什麼特殊的地方異步編程

public Users GetUserInfo(string userId)
{
    using (UserDbContext db = new UserDbContext())
    {
        var user = db.Users.FirstOrDefault(p => p.UserId = userId);
        return user;
    }
}

接下來咱們看看異步的實現代碼函數

public async Task<Users> GetUserInfoAsync(string userId)
{
    using (UserDbContext db = new UserDbContext())
    {
        var user = await db.Users.FirstOrDefaultAsync(p => p.UserId = userId);
        return user;
    }
}

以上兩段代碼看起來很是的相似,可是仔細看卻有明顯的不一樣。異步方法上多了一個async的標識,同時返回值User,被標識成了Task<Users>,同時在進行數據庫查詢的時候,使用到了await。這裏提早說一下await關鍵字,當編譯器看到await關鍵字的時候,會截斷方法,便於線程調度。簡單點說,就是當調用線程運行到FirstOrDefaultAsync時,查詢開始,但不是在當前線程,在新的線程裏面,咱們查詢完數據庫後,根據須要作進一步處理,好比,若是原線程UI線程,它將返回以繼續處理用戶的其餘操做(這裏很是相似回調方式),不然的話,這個線程就直接被釋放了。這段可能比較抽象,會在以後的系列裏進一步講解。性能

爲了更好的進行異步編程,咱們須要在方法簽名後面追加Async,這是一種異步編程的規約,也但願你們遵照。spa

雖然異步編程對系統以及用戶的體驗很是的有幫助,但若是對異步編程不甚瞭解,可能會發生一些使人感到詭異的問題,並且這些問題可能經過debug方式也很可貴到解決。線程

異步執行流程

一、想象一下,在現實世界中,一個顧客到電腦專賣店買東西,就是那種拿了就走的場景。若是店鋪只有一我的,在與顧客1沒有結算完成以前,對顧客2的請求,只能暫時放置一下。相信你們在現實世界中,確定會遇到相似的狀況,心情可能也很不爽,若是不是很迫切,多是再看看,換一家店,若是比較着急,就會一直催,而後也不必定會有迴應。debug

以下圖所示

二、有一天,老闆請了幾個夥計幫忙搬電腦,在顧客1沒有結算完成以前,老闆就能夠接住顧客2的需求,並經過信息系統或者大吼一嗓子的方式,讓電腦準備顧客2的電腦。同時,電腦把顧客1的電腦搬到前臺,由老闆去跟顧客結算,整個的流程就顯得體驗度很高,顧客也不會被忽略,賣出去的東西也多了不少,不過等待仍是要等的。

以下圖所示

 

寫在後面

本文主要介紹了異步編程的基礎,經過以上介紹,咱們知道要建立一個異步函數,首先須要用async去修飾一個方法,同時返回值類型必須是Task或者Task<T>,固然在使用UI控制器時間處理的時候是可使用async void的。在方法內部,須要使用await關鍵字。異步函數會被編譯器編譯成複雜的程序結構,能夠視其爲一種狀態機。不過須要提醒的是,若是不須要編寫異步函數,那就用同步。

雖然異步編程已經變得很是簡單,可是你們一樣須要瞭解異步編程背後的理念以及原理,這有助於咱們編寫高性能高擴展的應用程序。

相關文章
相關標籤/搜索