Asycn/Await 異步編程初窺

通過兩天密集型的學習,翻閱了大量 webpages ,點擊了很多重點 blogs,總算基本瞭解了一些 async/await 搭配使用的入門技巧,總結一下html

 

1. async/await 應該只是語法上的甜點,讓想使用異步方法運行程序的程序員可以專心專一代碼邏輯,而別被原來的 Begin... End... 型或是IAsync ...Async 的老式異步帶的愈來愈遠。想起剛試着編寫 Tcp Listener的時候,真是噩夢。異步響應必須放在另外一個回調方法或是事件中,而從異步響應產生的異步接收又必須再次放到另外一個回調方法或是事件中,更可怕的是,如何循環它們。程序員

2. async/await 標識的方法,「自己不主動建立額外線程」——這句話很容易讓人誤解。《Async 和 Await 異步編程的原理》這篇文章寫的比較詳細,異步,必然多線程,更況且是從 UI 線程啓動的。只是這種多線程被Framework透明掉了,使用者沒必要本身在這方面去走腦子怎麼建立線程,怎麼回收,怎麼捕捉異常,還得讓代碼好看一點。web

3. await 讓我開始的時候陷入了一個誤區,認爲使用 var result = await FunRun(...) 這種寫法,FunRun()方法就會異步運行而不會阻塞UI線程,這是錯的,我忽略了一個很嚴重的問題。先看一下原來錯誤的代碼:編程

 1 private async Task<TimeSpan> Download(Uri address, string fileName)
 2         {
 3             this.uri = address;
 4             this.fileName = fileName;
 5             DateTime start = DateTime.Now;
 6             //
 7             HttpWebRequest request;
 8             HttpWebResponse response = null;
 9             try
10             {
11                 request = (HttpWebRequest)WebRequest.Create(address);
12                 response = (HttpWebResponse)request.GetResponse();
13                 using (Stream httpStream = response.GetResponseStream())
14                 {
15                     using (FileStream writer = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read))
16                     {
17                         byte[] buffer = new byte[8192];
18                         int readLength = httpStream.Read(buffer, 0, buffer.Length); 
19                         //
20                         while (readLength > 0)
21                         {
22                             writer.Write(buffer, 0, readLength);
23                             readLength = httpStream.Read(buffer, 0, buffer.Length); 
24                         }
25                     }
26                 }
27             }
28             catch(Exception)
29             {
30                 if (response != null) { response.Close(); }
31             }
32 
33             return DateTime.Now - start;
34         }

代碼完成下載一個資源到指定位置的功能,自己邏輯沒有錯誤,看起來這彷佛是一個標準的帶有 async 標記和 Task<T> 返回類型的方法,因此我信心慢慢的調用了它。多線程

1 private async void button1_Click(object sender, EventArgs e)
2         {
3             //略過部分邏輯判斷的東西
4             ......
5 
6             TestApp.HttpDownloader.HttpDownloaderEngine hdEngine = new HttpDownloaderEngine();
7             var time = await hdEngine.Download(address, saveFileTextBox.Text);
8             MessageBox.Show(string.Format("下載完成,共耗時 {0} 秒", time.Seconds.ToString()));
9         }
調用錯誤寫法的方法

Button1 的 Click 事件自己也沒有問題,我還細心的加上了 async 標記(固然,不加也不讓我過去啊),一切很好我即刻運行,結果讓我很困惑,的確成功的下載了 Mp3 到個人電腦,可無論時間長短,個人 UI 依舊像同步的同樣,不能響應知道執行完成。問題處在哪裏?異步

人是須要休息的,學習->休息->消化,通過再次梳理和查看資料,我找出了第 3 點開頭我說的,Bug 在於 HttpDownloadEngine 的 Download 方法我雖然標記了 async,button_click 誤覺得 Download 方法能夠完成異步工做,button_click 是沒錯的,錯在 Download 方法內不,沒有任何「異步執行的代碼」!也就是說,Download 方法內沒有出現一個 await ,這使得標記了 async 的 Download 方法依舊是同步的,button_click 調用了一個同步方法在同步執行。async

如何修改呢,在 Download 方法內的關鍵處執行 await Task<T> ....Async ,如 readLength = await responseStream.ReadAsync(buffer, 0, buffer.Length);,關鍵處是指的確須要異步執行的地方。ide

4. 我要感謝 Microsoft,我不是大神,我是個愛好者,是微軟借鑑並創造了 .Net 和無與倫比的 VS,讓我和像我同樣的人都能領略計算機的更多魅力,這種魅力,來自於創造和分享給他人。異步編程

 

貼上一個下載的結果圖學習

相關文章
相關標籤/搜索