C#中的thread和task之Task
簡介
Task是在.NET Framework 4中添加進來的,這是新的namespace:System.Threading.Tasks;它強調的是adding parallelism and concurrency to applications。
現在都是多核的CPU,在系統內,Task Parallel Library能更有效地利用CPU核心。TPL 會動態地按比例調節并發程度,以便最有效地使用所有可用的處理器。TPL 還處理工作分區、ThreadPool 上的線程調度、取消支持、狀態管理以及其他低級別的細節操作。對比ThreadPool上的Thread并沒有很好地支持Cancel的操作。
在語法上,和lambda表達式更好地結合。
創建Task
顯式創建Task
先看一個簡單的示例:
using System; using System.Threading; using System.Threading.Tasks;public class TaskExample1 {public static void Main(){Thread.CurrentThread.Name = "Main";// 使用lambda方式,之間提供一個用戶delegate,創建一個TaskTask taskA = new Task( () => Console.WriteLine("From taskA."));// StarttaskA.Start();// Output a message from the calling thread.Console.WriteLine("From thread '{0}'.", Thread.CurrentThread.Name);//等待task結束taskA.Wait();} }// From thread 'Main'. // From taskA.任務對象Task提供可在任務的整個生存期內從調用線程訪問的方法和屬性。例如,可以隨時訪問任務的 Status 屬性,以確定它是已開始運行、已完成運行、已取消還是引發了異常。狀態由 TaskStatus 枚舉表示。
簡化創建并開始的Task操作版本–直接使用一個操作: System.Threading.Tasks.Task.Run()
using System; using System.Threading; using System.Threading.Tasks;public class TaskExample2 {public static void Main(){Thread.CurrentThread.Name = "Main";// Define and run the task.Task taskA = Task.Run( () => Console.WriteLine("From taskA."));// Output a message from the calling thread.Console.WriteLine("From thread '{0}'.", Thread.CurrentThread.Name);taskA.Wait();} } // From thread 'Main'. // From taskA.TaskFactory創建Task
TPL提供了工廠類TaskFactory,也可用直接創建Task。 一個操作System.Threading.Tasks.TaskFactory.StartNew, 即可完成創建并開始一個Task.
Use this method when creation and scheduling do not have to be separated and you require additional task creaion options or the use of a specific scheduler, or when you need to pass additional state into the task through its AsyncState property, as shown in the following example.
using System; using System.Threading; using System.Threading.Tasks;public class TaskExample3 {public static void Main(){Thread.CurrentThread.Name = "Main";// 創建task并啟動Task taskA = Task.Factory.StartNew(() => Console.WriteLine("From taskA."));// Console.WriteLine("From thread '{0}'.", Thread.CurrentThread.Name);// wait tasktaskA.Wait(); } }// Hello from thread 'Main'. // Hello from taskA.傳入參數
來自MS的示例:
using System; using System.Threading; using System.Threading.Tasks;public class Example {public static void Main(){Task[] taskArray = new Task[10];for (int i = 0; i < taskArray.Length; i++) {taskArray[i] = Task.Factory.StartNew( (int param) => {Console.WriteLine("Task #{0}.", param);},i );}Task.WaitAll(taskArray); } }Task返回值
如果一個Task執行方法是有返回值的,可用得到其值。在創建一個task時,其返回的值為Task,表示一個返回類型為T的Task;在taks完成執行后,可用通過Task的Result屬性獲取結果。
public class Task<TResult> : System.Threading.Tasks.Task
來自MS的示例:
using System; using System.Linq; using System.Threading.Tasks;class Program {static void Main(){// lambda表達式創建一個task并執行,并返回值。Task<int> task1 = Task<int>.Factory.StartNew(() => 1);int i = task1.Result;// 返回對象Task<Test> task2 = Task<Test>.Factory.StartNew(() =>{string s = ".NET";double d = 4.0;return new Test { Name = s, Number = d };});Test test = task2.Result;// Return an array produced by a PLINQ queryTask<string[]> task3 = Task<string[]>.Factory.StartNew(() =>{string path = @"C:\Users\Public\Pictures\Sample Pictures\";string[] files = System.IO.Directory.GetFiles(path);var result = (from file in files.AsParallel()let info = new System.IO.FileInfo(file)where info.Extension == ".jpg"select file).ToArray();return result;});foreach (var name in task3.Result)Console.WriteLine(name);}class Test{public string Name { get; set; }public double Number { get; set; }} }Continue操作
如果一個Task開始執行時間依賴于其它的Task的完成,可以使用Continue系列方法。
來自MS的示例:
using System; using System.Threading.Tasks;public class Example {public static void Main(){ var getData = Task.Factory.StartNew(() => { Random rnd = new Random(); int[] values = new int[100];for (int ctr = 0; ctr <= values.GetUpperBound(0); ctr++)values[ctr] = rnd.Next();return values;} ); var processData = getData.ContinueWith((x) => {int n = x.Result.Length;long sum = 0;double mean;for (int ctr = 0; ctr <= x.Result.GetUpperBound(0); ctr++)sum += x.Result[ctr];mean = sum / (double) n;return Tuple.Create(n, sum, mean);} ); var displayData = processData.ContinueWith((x) => {return String.Format("N={0:N0}, Total = {1:N0}, Mean = {2:N2}",x.Result.Item1, x.Result.Item2, x.Result.Item3);} ); Console.WriteLine(displayData.Result);} }// 輸出: // N=100, Total = 110,081,653,682, Mean = 1,100,816,536.82而且,可以使用更簡化的寫法.
using System; using System.Threading.Tasks;public class Example {public static void Main(){ var displayData = Task.Factory.StartNew(() => { Random rnd = new Random(); int[] values = new int[100];for (int ctr = 0; ctr <= values.GetUpperBound(0); ctr++)values[ctr] = rnd.Next();return values;} ). ContinueWith((x) => {int n = x.Result.Length;long sum = 0;double mean;for (int ctr = 0; ctr <= x.Result.GetUpperBound(0); ctr++)sum += x.Result[ctr];mean = sum / (double) n;return Tuple.Create(n, sum, mean);} ). ContinueWith((x) => {return String.Format("N={0:N0}, Total = {1:N0}, Mean = {2:N2}",x.Result.Item1, x.Result.Item2, x.Result.Item3);} ); Console.WriteLine(displayData.Result);} }Cancel操作
在TPL中,為Task能cancel執行,提供了CancellationTokenSource和CancellationToken;
需要完成的工作是:在Task的action執行方法內,周期性地檢查CancellationToken的IsCancellationRequested屬性。
示例:
總結
以上是生活随笔為你收集整理的C#中的thread和task之Task的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 密室逃脱3攻略有哪些
- 下一篇: C#中的Dispose模式