1、異步編程模型(APM)html
3、基於任務的異步模式(TAP),推薦使用 spring
4、C# 5.0 新特性——Async和Await使異步編程更簡單編程
這個只是簡化了數據綁定,跟ASP.NET MVC3不斷改進同樣,其實不是什麼亮點改進。服務器
comboBox1.Text :=: textBox1.Text; //將文本框的內容綁定到下拉框。
這個的加入給一些設計增長了強大功能,泛型早在C#2.0加入後就有着強大的應用,通常稍微設計比較好的框架,都會用到泛型,C#5.0加入帶參數泛型構造函數,則在原有基礎上對C#泛型完善了不少。:)框架
public class T MyClass : T: class, new() public class T MyClass : T:class, new(int)
這個是一個我很早就想若是能這樣就行了,沒想到在C#5.0裏就加入此功能,之前case裏只能寫一個具體的常量,而如今能夠加表達式了,靈活多了。異步
switch(myobj){ case string.IsNullorEmpty(myotherobj): ..... case myotherobj.Trim().Lower: .... }
咱們在C#3.0裏有擴展方法,那麼在C#5.0裏將會加入擴展屬性的感念,對照擴展方法,不難理解擴展屬性的概念了。如下爲擴展屬性的定義舉例:async
[Associate(string)] public static int MyExtensionProperty { get;set;}
int x? = null; int y? = x + 40; Myobject obj = null; Myotherobj obj2 = obj.MyProperty ??? new Myotherobj();
C# 5.0 提供的async和await使異步編程更簡單。異步編程
.NET 4.5 的推出,對於C#又有了新特性的增長——就是C#5.0中async和await兩個關鍵字,這兩個關鍵字簡化了異步編程。函數
async和await關鍵字只是編譯器的功能。編譯器最終會用Task類建立代碼。
創建一個同步方法Greeting,該方法在等待一段時間後,返回一個字符串。
private string Greeting(int delay, string name) { System.Threading.Thread.Sleep(delay); return string.Format("Hello, {0}.", name); }
定義一個方法GreetingAsync,可使方法異步化,其傳入的參數不作強制要求。基於任務的異步模式指定,並返回一個任務。注意,該方法返回的是Task<string>,定義了一個返回字符串的任務,與同步方法返回值一致。
private Task<string> GreetingAsync(string name, int delay = 3000) { return Task.Run<string>(() => { return Greeting(delay, name); }); }
可使用await關鍵字調用返回任務的異步方法GreetingAsync。可是,使用await關鍵字的方法必需要用async關鍵字修飾符聲明。在GreetingAsync方法完成前,被async關鍵字修飾的方法內await關鍵字後面的代碼不會繼續執行。可是,啓動被async關鍵字修飾的方法的線程能夠被重用,而沒有被阻塞。
public async void CallerWithAsync() { string result = await GreetingAsync("Nigel", 2000); Console.WriteLine(result); }
注意:async修飾符修飾只能用於返回Task或void的方法。不能做爲程序的入口點,即Main方法不能使用async修飾符。await修飾符只能用於返回Task的方法。
void Main() { DisplayValue(); System.Diagnostics.Debug.WriteLine("MyClass() End."); } public async void DisplayValue() { double result = await GetValueAsync(1234.5, 1.01);//此處會開新線程處理GetValueAsync任務,而後方法立刻返回 //這以後的全部代碼都會被封裝成委託,在GetValueAsync任務完成時調用 System.Diagnostics.Debug.WriteLine("Value is : " + result); } public Task<double> GetValueAsync(double num1, double num2) { return Task.Run(() => { for (int i = 0; i < 1000000; i++) { num1 = num1 / num2; } return num1; }); }
上面在MyClass的構造函數裏調用了async關鍵字標記的異步方法DisplayValue(),DisplayValue()方法裏執行了一個await關鍵字標記的異步任務GetValueAsync(),這個異步任務必須是以Task或者Task<TResult>做爲返回值的。
而咱們也看到,異步任務執行完成時實際返回的類型是void或者TResult,DisplayValue()方法裏await GetValueAsync()以後的全部代碼都會在異步任務完成時纔會執行。
DisplayValue()方法實際執行的代碼以下:
public void DisplayValue() { System.Runtime.CompilerServices.TaskAwaiter<double> awaiter = GetValueAsync(1234.5, 1.01).GetAwaiter(); awaiter.OnCompleted(() => { double result = awaiter.GetResult(); System.Diagnostics.Debug.WriteLine("Value is : " + result); }); }
能夠看到,async和await關鍵字只是把上面的代碼變得更簡單易懂而已。
程序的輸出以下:
MyClass() End.
Value is : 2.47032822920623E-322
考慮如下代碼:
async int M() { return await F(); }
其中F()是一個異步方法,它返回的是Task<int>對象。
這段代碼事實上等價於:
async int M() { int r = await F(); return r; }
注意和
async Task<int> M() { return F(); }
區分。後面這段代碼是一個同步方法,它只會返回F()的真實返回值。
// 使用C# 5.0中提供的async 和await關鍵字來定義異步方法 // 從代碼中能夠看出C#5.0 中定義異步方法就像定義同步方法同樣簡單。 private async Task<long> AccessWebAsync() { MemoryStream content = new MemoryStream(); // 對MSDN發起一個Web請求 HttpWebRequest webRequest = WebRequest.Create("http://msdn.microsoft.com/zh-cn/") as HttpWebRequest; if (webRequest != null) { // 返回回覆結果 using (WebResponse response = await webRequest.GetResponseAsync()) { using (Stream responseStream = response.GetResponseStream()) { await responseStream.CopyToAsync(content); } } } txbAsynMethodID.Text = Thread.CurrentThread.ManagedThreadId.ToString(); return content.Length; } private void OtherWork() { this.richTextBox1.Text += "\r\n等待服務器回覆中.................\n"; }
運行結果以下:
咱們對比下上面使用async和await關鍵字來實現異步編程的代碼和在第二部分的同步代碼,有沒有發現使用async和await關鍵字的異步實現和同步代碼的實現很像,只是異步實現中多了async和await關鍵字和調用的方法都多了async後綴而已。正是由於他們的實現很像,因此我在第四部分才命名爲使用async和await使異步編程更簡單,就像咱們在寫同步代碼同樣,而且代碼的coding思路也是和同步代碼同樣,這樣就避免考慮在APM中委託的回調等複雜的問題,以及在EAP中考慮各類事件的定義。
下面再分享下幾個關於async和await常問的問題
問題一:是否是寫了async關鍵字的方法就表明該方法是異步方法,不會堵塞線程呢?
答: 不是的,對於只標識async關鍵字的(指在方法內沒有出現await關鍵字)的方法,調用線程會把該方法當成同步方法同樣執行,因此然而會堵塞GUI線程,只有當async和await關鍵字同時出現,該方法才被轉換爲異步方法處理。
問題二:「async」關鍵字會致使調用方法用線程池線程運行嗎?
答: 不會,被async關鍵字標識的方法不會影響方法是同步仍是異步運行並完成,而是,它使方法可被分割成多個片斷,其中一些片斷可能異步運行,這樣這個方法可能異步完成。這些片斷界限就出如今方法內部顯示使用」await」關鍵字的位置處。因此,若是在標記了」async」的方法中沒有顯示使用」await」,那麼該方法只有一個片斷,而且將以同步方式運行並完成。在await關鍵字出現的前面部分代碼和後面部分代碼都是同步執行的(即在調用線程上執行的,也就是GUI線程,因此不存在跨線程訪問控件的問題),await關鍵處的代碼片斷是在線程池線程上執行。總結爲——使用async和await關鍵字實現的異步方法,此時的異步方法被分紅了多個代碼片斷去執行的,而不是像以前的異步編程模型(APM)和EAP那樣,使用線程池線程去執行一整個方法。
爲了便於調試,C#5.0提供了一種新特性:CallerInfoAttributes。它包括三個主要的類:
該功能主要是用於調試,示例代碼以下:
在本示例中,咱們添加了一個Log函數,以對程序進行日誌記錄,並在主函數中進行調用。
using System; using System.Runtime.CompilerServices; namespace TestPro { class Program { public static void Main() { Log("Test."); } // 對日誌消息進行記錄,同時全部內容均有默認值,若是獲取失敗,則使用默認值。 public static void Log(string message, [CallerMemberName] string callerName = "unknown", [CallerFilePath] string callerFilePath = "unknown", [CallerLineNumber] int callerLineNumber = -1) { Console.WriteLine("Message: {0}", message); Console.WriteLine("Caller's Name: {0}", callerName); Console.WriteLine("Caller's FilePath: {0}", callerFilePath); Console.WriteLine("Caller's LineNumber: {0}", callerLineNumber); } } }
程序執行之後會顯示如下內容。
Message: Test. Caller Name: Main Caller FilePath: C:\Users\Administrator\source\repos\TestPro\Program.cs Caller Line number: 10 請按任意鍵繼續. . .