首先,在mvc中如果要用純異步請不要使用async和await,可以直接使用Task.Run。
其次,在mvc中使用async和await可以讓系統開新線程處理Task的代碼,同時不必等Task執行結束,就可以同時運行Task之后的代碼,加快效率。
要注意的是:如果使用async和await,系統雖然可以同時處理多個事務,但客戶端(瀏覽器)不會有響應,依然要等到所有代碼全部執行完畢(包括異步的代碼)才能正常響應。
/* * 演示如何利用 .net 4.5 的新特性實現異步操作 * * 什么場景下需要異步操作? * 在因為磁盤io或網絡io而導致的任務執行時間長的時候應該使用異步操作,如果任務執行時間長是因為cpu的消耗則應使用同步操作(此時異步操作不會改善任何問題) * 原理是什么? * 在 Web 服務器上,.NET Framework 維護一個用於服務 ASP.NET 請求的線程池(以下把 .NET Framework 維護的用於服務 ASP.NET 請求的線程池稱作為“特定線程池”) * 同步操作時,如果特定線程池利用滿了,則不會再提供服務 * 異步操作時: * 1、一個請求過來,特定線程池出一個線程處理此請求 * 2、啟動一個非特定線程池中的另一個線程處理異步操作,此時處理此請求的線程就會空出來,不會被阻塞,它可以繼續處理其它請求 * 3、異步操作執行完畢后,從特定線程池中隨便找一個空閑線程返回請求結果 */
實際工作中,async和await我們可以用於類似用戶上傳頭像、上傳照片這種的耗時較長的功能中,我們可以在邊上傳照片時邊處理數據庫的其他事務。
而純異步則多用於時間較長,而無需結果實時看反饋給用戶的操作,例如:管理在后台備份數據庫、清理垃圾文件等。
如果async和await的異步方法是有返回值的,而且主方法中又要使用這個返回值,那么將不會實現多個異步方法同時執行,要等異步結果后才繼續執行,相當於異步並未起到多程序同時處理事務的目的。這僅是對於Web或控制台程序而言的,如果對於Winform則有大大的不同,因為Winform如果使用異步時界面是可以響應的。
Web中異步更多的是用來實現大量IO操作,或大量調用WCF、WebService時使用。
所以,在Mvc這種Web界面中使用async和await異步的實際意義就不是很大了,因為界面總是沒有響應的,而且也無法實現多線程同時工作。
有需要請看這篇:http://www.dozer.cc/2012/03/async-and-await-in-web-application/
async的作用是異步執行,await的作用是等待執行結果(會卡住異步方法中await以下的代碼,但不會卡死主線程)。
async一般最終都需要一個async void方法來進行最高層的調用。比如:private async void Sync_Button_Click(object sender, RoutedEventArgs e),C#中也提供了大量的可設置async的系統方法和事件。
class Program { private static async void Test() { Task<int> t = new Task<int>(() => { Thread.Sleep(3000); return 1; }); t.Start(); int tr = await t; Console.WriteLine(tr); } static void Main(string[] args) { Test(); Console.WriteLine("Main"); Console.ReadKey(); } }
Test函數就用最簡單的方法使用了這兩個關鍵字,執行這段代碼,首先輸出“Main”,然后3秒鍾后會輸出“1”。
也可以使用:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ConsoleApplication11 { class Program { static void Main(string[] args) { Test(); Console.WriteLine("Main"); Console.ReadKey(); } private static async void Test() { var t = Task<int>.Run(() => { Thread.Sleep(3000); return 1; }); Console.WriteLine(await t); } } }
使用async異步編程時,請注意如下事項:
-
async void 函數只能在UI Event回調中使用。
-
async void 函數中一定要用try-catch捕獲所有異常,否則會很容易導致程序崩潰。
-
async void 類型的lambda表達式非常隱蔽,並且容易在無意中編寫出來,尤其需要注意。
-
不要忽視CS4014告警,更不要為了消除CS4014告警而改用 async void 函數。
確實無需等待的 async Task 函數用我前面寫的擴展函數 IgnorCompletion 消除 這個告警。 -
注冊 TaskScheduler.UnobservedTaskException事件 ,記錄Task中未處理異常信息,方便分析及錯誤定位。(注意,這個回調里面不能進行耗時操作,具體原因參看前面的老趙的那篇Blog)
private async void Sync_Button_Click(object sender, RoutedEventArgs e) { 2: OutputTextBlock.Text += "開始" + Environment.NewLine; 3: // 這裡會等 getFileContentAsync() 執行完畢後, 再執行貼上結束字串那一行 4: // 因為 Compiler 會再 await 這行下斷點 5: OutputTextBlock.Text += await getFileContentAsync(); 6: OutputTextBlock.Text += "結束" + Environment.NewLine; 7: } 8: 9: private async Task<string> getFileContentAsync() { 10: StorageFolder folder = KnownFolders.DocumentsLibrary; 11: StorageFile file = await folder.GetFileAsync(TESTED_FILE_NAME); 12: var result = await FileIO.ReadTextAsync(file) + Environment.NewLine; 13: return result; 14: }