C# Task中的Func, Action, Async與Await的使用
在說Asnc和Await之前,先說明一下Func和Action委托, Task任務的基礎的用法
1. Func
Func是一種委托,這是在3.5裏面新增的,2.0裏面我們使用委托是用Delegate,Func位於System.Core命名空間下,使用委托可以提升效率,例如在反射中使用就可以彌補反射所損失的性能。
Action<T>和Func<T,TResult>的功能是一樣的,只是Action<T>沒有返類型,
Func<T,T,Result>:有參數,有返回類型
Action,則既沒有返回也沒有參數,
Func<T,TResult>
的表現形式分為以下幾種:
1。Func<T,TResult>
2。Func<T,T1,TResult>
3。Func<T,T1,T2,TResult>
4。Func<T,T1,T2,T3,TResult>
5。Func<T,T1,T2,T3,T4,TResult>
分別說一下各個參數的意義,TResult表示
委托所返回值 所代表的類型, T,T1,T2,T3,T4表示委托所調用的方法的參數類型,
以下是使用示例:
1 Func<int, bool> myFunc = null;//全部變量 2 3 myFunc = x => CheckIsInt32(x); 4 //給委托封裝方法的地方 使用了Lambda表達式 5 6 private bool CheckIsInt32(int pars)//被封裝的方法 7 { 8 return pars == 5; 9 } 10 11 bool ok = myFunc(5);//調用委托
MSDN:http://msdn.microsoft.com/zh-cn/library/bb534303(VS.95).aspx
2. Action
但是如果我們需要所封裝的方法不返回值,增麽辦呢?就使用Action!
可以使用
Action<T1, T2, T3, T4>委托以參數形式傳遞方法,而不用顯式聲明自定義的委托。封裝的方法必須與此委托定義的方法簽名相對應。也就是說,封裝的方法必須具有四個均通過值傳遞給它的參數,並且不能返回值。(在 C# 中,該方法必須返回 void。在 Visual Basic 中,必須通過 Sub…End Sub 結構來定義它。)通常,這種方法用於執行某個操作。
使用方法和Func類似!
Action:既沒有返回,也沒有參數,使用方式如下:
1 Action action = null;//定義action 2 3 action = CheckIsVoid;//封裝方法,只需要方法的名字 4 5 action();//調用
MSDN:http://msdn.microsoft.com/zh-cn/library/bb548654(VS.95).aspx
總結:
使用Func<T,TResult>和Action<T>,Action而不使用Delegate其實都是為了簡化代碼,使用更少的代碼達到相同的效果,不需要我們顯示的聲明一個委托。
Func<T,TResult>的最後一個參數始終是返回類型,而Action<T>是沒有返回類型的,而Action是沒有返回類型和參數輸入的.
3. Task
使用 Async 和 Await 的異步編程(msdn的好文章) : https://msdn.microsoft.com/zh-cn/library/hh191443(v=vs.120)
Task基本使用: C# 線程知識--使用Task執行異步操作
Task和await結合返回值見: .NET(C#):await返回Task的async方法
Task深入了解見: C# Task的使用
總結: Task提供一種新的類似多線程的多任務的用法, 達到使用線程的效果,但具體怎麽分配線程由.net底層控制,這樣性能好,效率也高,我們只需要專註業務邏輯, 同時具備以前線程不具備的返回值的功能(可以通過回調事件來處理),而在Task中只是簡單的使用await來使用, await的task相當於同步的調用task, 同時會有返回值,只是在書寫方面需要註意async, task,func, action等等關鍵字的使用,新手可能很困惑, 下面的例子就是一個簡單的task使用例子,新手註意註釋!!!
1 static void Main(string[] args) 2 { 3 //異步方法, 當中使用await可以執行task異步任務,否則當作同步執行 4 test(); 5 //其次輸出,因為異步進入task任務了,就同步執行當前線程下面的代碼 6 log("Main:調用test後"); 7 Thread.Sleep(Timeout.Infinite); 8 } 9 10 //Main方法不允許加async,所以我們用這個方法使用await 11 static async void test() 12 { 13 //最先輸出,還沒有進入task 14 log("test: await之前"); 15 // await後的內容會被加在目標doo的Task的後面,然後test馬上返回,而doo則是進入了另一個任務執行了 16 log("doo的Task的結果: " + await doo()); 17 // 會等到上面await執行的任務完成後才會執行當前代碼 18 log("test: await之後"); 19 } 20 //返回Task的async方法, 一個標準的帶返回值的異步task任務方法 21 static async Task<int> doo() 22 { 23 // 簡單的說, async中使用await就是異步中以同步方式執行Task任務的方法,task任務一個接一個執行. 24 var res1 = await Task.Run(() => { Thread.Sleep(1000); log("Awaited Task1 執行"); return 1; }); 25 var res2 = await Task.Run(() => { Thread.Sleep(1000); log("Awaited Task2 執行"); return 2; }); 26 var res3 = await Task.Run(() => { Thread.Sleep(1000); log("Awaited Task3 執行"); return 3; }); 27 28 //不使用await:線程池多線程, 當前task不會等這個執行完,因為不是await,只是又開啟了一個線程 29 ThreadPool.QueueUserWorkItem(_ => 30 { 31 Thread.Sleep(1000); 32 log("ThreadPool.QueueUserWorkItem: 線程池多線程執行"); 33 }); 34 35 //不使用await:Task多線程, 當前task不會等這個執行完,因為不是await,只是又開啟了一個任務 36 Task.Run(() => 37 { 38 Thread.Sleep(1000); 39 log("Task.Run: Task多線程執行"); 40 41 }); 42 43 return res1 + res2 + res3; 44 } 45 //輸出方法:顯示當前線程號和輸出信息 46 static void log(string msg) 47 { 48 Console.WriteLine("線程{0}: {1}", Thread.CurrentThread.ManagedThreadId, msg); 49 }
執行結果如下:
4. Async、Await
這個是.NET 4.5的特性,所以要求最低.NET版本為4.5。
看很多朋友還是使用的Thread來使用異步多線程操作,基本上看不見有使用Async、Await進行異步編程的。各有所愛吧,其實都可以。只要正確使用就行,不過還是寫了這篇文章推薦大家使用Async、Await。 原因就是:可以跟寫同步方法一樣去異步編程。代碼則就非常的清晰,就跟寫普通的代碼一樣,不用關系如何去異步編程,也讓很多初級程序員也能夠異步編程了。下面是一個使用Thread 多線程實現的異步例子,以及一個使用Async與Await的異步例子,接下來我們再簡單理解下Async與Await的相關技術說明。
Thread多線程異步編程例子
class Program { static void Main(string[] args) { Console.WriteLine("主線程測試開始.."); Thread th = new Thread(ThMethod); th.Start(); Thread.Sleep(1000); Console.WriteLine("主線程測試結束.."); Console.ReadLine(); } static void ThMethod() { Console.WriteLine("異步執行開始"); for (int i = 0; i < 5; i++) { Console.WriteLine("異步執行" + i.ToString() + ".."); Thread.Sleep(1000); } Console.WriteLine("異步執行完成"); } }
以上代碼運行效果如下圖
使用Async與Await進行異步編程
1 static void Main(string[] args) 2 { 3 Console.WriteLine("主線程測試開始.."); 4 AsyncMethod(); 5 Thread.Sleep(1000); 6 Console.WriteLine("主線程測試結束.."); 7 Console.ReadLine(); 8 } 9 10 static async void AsyncMethod() 11 { 12 Console.WriteLine("開始異步代碼"); 13 var result = await MyMethod(); 14 Console.WriteLine("異步代碼執行完畢" + result.ToString()); 15 } 16 17 static async Task<int> MyMethod() 18 { 19 for (int i = 0; i < 5; i++) 20 { 21 Console.WriteLine("異步執行" + i.ToString() + ".."); 22 await Task.Delay(1000); //模擬耗時操作 23 } 24 return 100; 25 }
運行效果:
顯而易見我們就跟寫同步方法一樣,完成了異步方法的編寫,代碼更清晰了。
只有擁有async才能在其內部使用await關鍵字。異步方法可以具有Task、Task<>或void的返回類型;
await關鍵字則是用於返回值是“可等待”類型(awaitable)的方法
C# Task中的Func, Action, Async與Await的使用