Async in C# 5.0(C#中的非同步編程Async) 蝸牛翻譯之第一章 ...
寫在前面
在學非同步,有位園友推薦了《async in C#5.0》,沒找到中文版,恰巧也想提高下英文,用我拙劣的英文翻譯一些重要的部分,純屬娛樂,簡單分享,保持學習,謹記謙虛。
如果你覺得這件事兒沒意義翻譯的又差,盡情的踩吧。如果你覺得值得鼓勵,感謝留下你的贊,祝各位愛技術的園友在今後每一次應該猛烈突破的時候,不選擇知難而退。在每一次應該獨立思考的時候,不選擇隨波逐流,應該全力以赴的時候,不選擇儘力而為,不辜負每一秒存在的意義。
轉載和爬蟲請註明原文鏈接http://www.cnblogs.com/tdws/p/5617242.html,博客園 蝸牛 2016年6月26日。
目錄 第1章 非同步編程介紹 讓我們從C#5.0非同步編程Async和他將對你意味著什麼來開始介紹吧! 非同步編程如果我們在一個耗時的操作中使用非同步的代碼,在其執行過程中,我們不需要無謂的等待。這種方式和在耗時操作的整個執行過程中的阻塞型代碼是相對的。
我們所說的耗時操作包括:
·網路請求
·硬碟數據訪問
·延遲一段時間的操作
全部的區別在於正在運行代碼的線程。在廣泛應用的編程語言當中,你的代碼運行在操作系統的線程中。如果在遇到耗時操作時,你的線程可以繼續去做其他事情,這就是非同步編程。如果你的線程除了等待什麼也不做,那就是同步的或者說是阻塞型代碼。
當然我們還有第三種方式去處理耗時操作—輪詢。這是一種不斷重覆“詢問”耗時操作是否完成的操作。儘管它在處理段時間操作上有自己的地位,但這通常不是一個好的解決方案。
你也許在過去的工作中使用過非同步編程。你可能開啟一個新的線程或者使用線程池,這也是非同步編程,因為你所工作的線程可以不被阻塞地去繼續做其他事情。而你的console app,像Console.ReadLine(),這就是阻塞型,在web app中,如果也是這樣的設計等待用戶輸入,將會是多麼糟糕呀。
非同步編程中很常見的難點在於這個操作在什麼時候結束,以便於執行下一步的某些操作。但是這在阻塞型代碼中,很容易做到:你只需要在將接下來的代碼寫在耗時操作的下一行就好。如果不加以處理,這種方式在非同步的世界中是怎樣也行不通的。因為幾乎可以確定的是,你下一行代碼是在耗時操作完成之前就已經執行了。
為瞭解決這個問題,我們發明瞭一些方式,為了在後臺操作完成後去執行下一步操作:
·將下一步操作所需的代碼插在耗時操作代碼主體的後面
·註冊一個當耗時操作結束時會觸發的方法
·在完成後傳遞委托或者Lambad(回調)
如果你下一個操作需要在特定的線程上執行(例如Winform和WPF的UI線程),你還需要在這個線程上安排隊列排序,這是很複雜的。
非同步代碼有什麼了不起的?非同步編程釋放了它開始的線程,這有許多原因確實不錯。首先,線程占用並且占用很少的資源,通常只用一個線程就可以完成主要的工作,就像UI線程,但是如果你不儘快釋放它,你的app就會出現未響應狀態。我們將會討論更多的原因在下一章。
最重要的,也是最令我激動的一點是:非同步編程讓我們得以有機會去盡情享受電腦並行計算帶來的好處。非同步編程讓我們以新的並且合理的方式構建應用程式,用更細粒度的並行和無需編寫難以維護的複雜代碼。第十章將會詳細探討此可能性。
什麼是非同步編程?在C#5.0當中,微軟編譯器團隊為我們增加了一個強大的新功能。
它以兩個新型關鍵字出現:。
·async
·await
它當然依賴於一些環境,要求你使用.NET FrameWork4.5,才能你的async代碼有用。
Async是屬於C#編譯器的一個功能,不能被封裝到一個類庫,它對你的源代碼進行改造,就像在早期C#版本對Lambda和迭代器所做的事情一樣。
通過免去早期C#版本非同步編程所需的複雜模式和代碼,這個新功能使非同步變得非常簡單。有了這個功能,我們可以合理地用非同步編程的風格編寫整個項目。
非同步編程一直在C#中是可行的的,它以前涉及編程者大量的手工工作,現在C#的async關鍵出現後,非同步編程的使用變得非常容易。
非同步編程Async做了什麼?Async功能提供了一種讓你表達在耗時操作後需要做什麼事情(執行什麼代碼)的方式,並且它易讀易懂,表現為非同步編程。
Async方法被編譯器轉化的像你平時所寫的阻塞代碼,這裡有一段簡單的下載網頁的阻塞型代碼:
private void DumpWebPage(string uri) { WebClient webClient = new WebClient(); string page = webClient.DownloadString(uri); Console.WriteLine(page); }
這裡還有一段使用Async實現相同功能的代碼:
private asyncvoid DumpWebPageAsync(string uri) { WebClient webClient = new WebClient(); string page = awaitwebClient.DownloadStringTaskAsync(uri); Console.WriteLine(page); }
兩段代碼在錶面上看起來是非常相似的,但是在其外表下,有很大的不同。
被標記為Async的方法,要求方法使用await關鍵字,為了遵循慣例,我們也再方法的尾碼名加上了Async。
有趣的地方是await關鍵字,當編譯器遇到它時,他將方法分開(chop the method up),事實上它是很複雜的,所以現在我介紹一個我覺得更易於理解的簡單情況的假結構。
1.await後所有的代碼被分離到另一個方法。
2.我們使用一個新版本叫做DownloadStringTaskAsync的DownloadString方法,它做和原版相同的事情,但它是非同步的。
3.這意味著我們可以給它新的第二種方法,即在它完成時它會調用。我們使用一些“魔法”來做這件事,稍後我會告訴你。
4.當下載結束,它將會把我們調用回來帶著已經下載好的可以使用的string字元串,在這種情況下,寫到控制台。
//這就是await分解的方法,上文所說的假的結構(譯者博客園蝸牛註解) private void DumpWebPageAsync(string uri) { WebClient webClient = new WebClient(); webClient.DownloadStringTaskAsync(uri)<- magic(SecondHalf); //魔力的方法調回來 } private void SecondHalf(string awaitedResult) { string page = awaitedResult; Console.WriteLine(page); }
當它運行此代碼時,調用線程會發生什麼?當線程抵達DownloadStringTaskAsync方法,下載工作開始,但並不在此線程中執行,在這個線程上,我們抵達了方法的結尾或者說是return,這個線程下一步做什麼由我們調用者來決定。如果是UI線程,它將會返回執行用戶操作,除此外,它的資源將會被釋放,這意味著我們在做非同步編程!
非同步編程並不能解決所有問題非同步代碼被微軟編譯器開發團隊儘可能設計的像你常寫的阻塞(同步)代碼,我們可以把耗時操作或者遠程操作處理地像本地操作和快速。但是保持和非同步調用一樣的性能和優勢。
然而,這樣的設計不是讓你忘記Async是後臺操作還有發生回調。你需要小心很多事情,包括:
·異常和try-catch-finally模塊
·方法的返回值
·線程和上下文
·性能
如果不瞭解它真正發生了什麼,你的應用程式可能會意想不到的掛掉,並且你將無法理解異常信息和沒有能力去解決問題。
寫在最後
終於翻譯好了第一章,四頁,花了幾個小時。昨天讀了一遍,沒讀懂,今天翻譯一遍果然收穫頗多。如果您表示支持,給個贊吧!繼續閱讀下一章 我們有什麼理由使用Async非同步編程