讓咱們再爲C#異步編程Async正名

本文版權歸博客園和做者吳雙本人共同全部。轉載和爬蟲必須在顯要位置註明出處:http://www.cnblogs.com/tdwshtml

半年前翻譯了一系列很糟糕的異步編程文章,用異步的經常使用語來講:」在未來的某個時間「 我還會從新翻譯Async in C#5.0 http://www.cnblogs.com/tdws/p/5617242.htmlchrome

 寫在前面 

  

       異步編程在處理併發方面被使用的愈來愈多,之因此說上面一句話,是爲了區分多線程編程。各位司機都知道,實際上異步編程的核心目標正併發處理。可仍是常常有一些讓人感到很無奈的說法和問題,好比說,異步編程能提升應用性能嗎?他能縮短我處理任務的時間嗎?他阻塞線程嗎?若是不阻塞線程,斷點爲何不繼續向下執行,個人哥!線程釋放到哪兒去了?我都讀書少你別騙我,線程都釋放了程序怎麼運行?前臺我用了Ajax,後臺使用Async有必要嗎?也許若是做爲司機的你看到最後一個問題,你只好攤手┑( ̄Д  ̄)┍。編程

 多線程場景理解

也許在某些時刻,你想提升應用程序執行速度,儘快拿到一個結果。這個時候,應該選擇的絕對不是Async和Task。打個比方說,你和你老婆週末去超市購物,剛一進超市門你發現結帳的每條隊伍都幾十人,因而你用到了多線程,你去排隊,一我的一我的的往前走,你老婆在另外一頭抓緊購物,在你快走到收銀臺的時候,你老婆來把購物車推給了你,因而大家直接結帳回家。雖然這種行爲很不文明,但這就是多線程,和異步編程一點關係都沒有。windows

 

 異步編程場景理解

那異步編程是什麼狀況,能解決什麼問題呢?你和你老婆開了一家麪包店,在初期只有你倆爲顧客服務。沒想到新店開張這麼火,每分鐘來一個顧客,而烤好一份麪包須要兩分鐘。每來一位顧客你都拿着一片面包去後廚烤箱烤,而且你要和你老婆要花兩分鐘來等各自的烤箱完成任務。但是你等待的這兩分鐘,又來了兩位顧客,着這樣的速度下去,根本不能知足顧客們的需求呀!你已經發現你和你老婆的問題了:那就是你和你老婆這兩條線程,都被烤箱花費的時間阻塞了!服務器

你和你老婆爲了解決阻塞的問題,又買了兩臺烤箱,而且爲了不新進顧客沒人服務,每當你把麪包送進烤箱後,標記其屬於哪位顧客後當即返回,準備接待新的顧客,再有顧客光臨,立馬接待,並將新的麪包送進另外一個烤箱並標記,並當即返回等待爲其餘人服務。在麪包烤好後,烤箱會以「叮」一聲,注意在這一信號到達後,並非必定要你去後廚烤箱取麪包,而是你和你老婆誰不忙誰去取。這樣處理後,高併發的顧客量,對你來講就顯得駕輕就熟了。你和你老婆作爲兩條線程,能夠不斷地以非阻塞的形式(不等烤箱),返回到顧客面前。可是須要注意的是不阻塞的概念,他不是讓你的程序繼續向下執行。就烤麪包而言你的一個烤麪包方法是這樣的:網絡

1.送入麪包到烤箱 2.烤箱處理麪包並給你結果 3.拿到麪包送到顧客。因此說「不阻塞」的概念,不能讓你直接作到第三步。在不阻塞期間,是沒有線程在你的這個方法中的,這個方法仍是要按照時間等待,等待在將來某個時刻的信號喚醒你或者你老婆,此時該方法恢復執行。因此說程序執行的時間依然不變,獲得優化的是處理併發的能力,你店裏(服務器)的吞吐量。多線程

 看着代碼理解

 異步編程應當被適用於IO密集型場景,非CPU計算密集場景。你們知道線程受CPU調度,若是你是四核CPU,那麼在你的線程池中,擁有四個線程,進程每一個虛擬CPU分配一個線程的時候,性能表現會最棒。既能高效運用CPU,又不用來回切換上下文損耗性能。你想一想,CPU密集的場景中,CPU就是要佔用你的線程,在這個時候異步編程沒有任何用處。然而在IO場景中,文件IO由win32用戶模式的API到windows內核模式,在內核模式中操做磁盤驅動程序。這期間,你的線程阻塞在驅動程序的響應中。而異步編程中,你的操做通知到磁盤驅動程序後,線程當即返回而非等待,在未來的某個時刻,驅動程序處理結束,處理結果放入CLR線程池隊列中,恢復狀態機,線程池中任意線程取出結果,方法繼續向下執行。在網絡IO中也是如此,只不過驅動程序變成了網絡驅動程序。請看以下代碼:併發

public static async Task<string> DoSomeAsync()
        {
            using (var client = new HttpClient())
            {
                var result = await client.GetAsync(
                    "http://stackoverflow.com/questions/37991851/jenkins-configure-page-not-loading-version1-651-3-chrome-browser")
                    .Result.Content.ReadAsStringAsync();
                Console.WriteLine(result);
                //作一些其餘操做
                var res = 1 + 1;
                //----------------
                return "";
            }
        }

在編譯的時候,DosomeAsync會被編譯成一個狀態機方法,狀態機是什麼先別管,你能夠把它當成一個黑盒子。在遇到GetAsync的時候,在DoSomeAsync中返回一個Task任務對象,並由await在Task對象上傳遞用於恢復狀態機的方法,至關於調用了ContinueWith().這個方法顧名思義,以xxx繼續。而後線程從DoSomeAsync中返回。返回後幹嗎去了?該線程能夠去處理其餘事情了。在未來某一時刻,服務器向咱們發送了一個相應,網絡驅動程序得知請求完畢,恢復該方法繼續執行剩下的其餘代碼。配一張亂糟糟的圖異步

 

 額外的好處

 在GC的垃圾清理執行過程當中,應用程序的全部線程都會被掛起,使用異步編程意味着在相同的併發量下,你可使用更少的線程來完成處理,額外帶來的好處就是,所須要清理的線程是更少的。還有一點就是,所使用的線程少了,CPU線程切換也變得更少。async

 

若是個人點滴分享對你有點滴幫助,歡迎點擊下方紅色按鈕關注,我將持續輸出分享。也歡迎爲我也爲你本身點贊。


本文關鍵字,C# ASP.NET 異步編程 MVC Async await

額外閱讀:異步編程最佳實踐  https://msdn.microsoft.com/zh-cn/magazine/jj991977.aspx

相關文章
相關標籤/搜索