.net 基於任務的非同步程式設計
阿新 • • 發佈:2020-12-02
-------------------------------------------------------隱式建立和執行任務--------------------------------------------------------------
Parallel.Invoke 方法提供了一種簡便方式,可同時執行任意數量的任意語句。 只需為每個工作項傳入 Action 委託即可。 建立這些委託的最簡單方式是使用 lambda 表示式。 lambda 表示式可呼叫指定的方法,或提供內聯程式碼。 下面的示例演示一個基本的 Invoke 呼叫,該呼叫建立並啟動同時執行的兩個任務。 第一個任務由呼叫名為 DoSomeWork
的方法的 lambda 表示式表示,第二個任務由呼叫名為 DoSomeOtherWork
的方法的 lambda 表示式表示。
Parallel.Invoke(() => DoSomeWork(), () => DoSomeOtherWork());
namespace ParallelTasks { using System; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks;View Codeusing System.Net; class ParallelInvoke { static void Main() { // Retrieve Goncharov's "Oblomov" from Gutenberg.org. string[] words = CreateWordArray(@"http://www.gutenberg.org/files/54700/54700-0.txt"); #region ParallelTasks // Perform three tasks in parallel on the source arrayParallel.Invoke(() => { Console.WriteLine("Begin first task..."); GetLongestWord(words); }, // close first Action () => { Console.WriteLine("Begin second task..."); GetMostCommonWords(words); }, //close second Action () => { Console.WriteLine("Begin third task..."); GetCountForWord(words, "sleep"); } //close third Action ); //close parallel.invoke Console.WriteLine("Returned from Parallel.Invoke"); #endregion Console.WriteLine("Press any key to exit"); Console.ReadKey(); } #region HelperMethods private static void GetCountForWord(string[] words, string term) { var findWord = from word in words where word.ToUpper().Contains(term.ToUpper()) select word; Console.WriteLine($@"Task 3 -- The word ""{term}"" occurs {findWord.Count()} times."); } private static void GetMostCommonWords(string[] words) { var frequencyOrder = from word in words where word.Length > 6 group word by word into g orderby g.Count() descending select g.Key; var commonWords = frequencyOrder.Take(10); StringBuilder sb = new StringBuilder(); sb.AppendLine("Task 2 -- The most common words are:"); foreach (var v in commonWords) { sb.AppendLine(" " + v); } Console.WriteLine(sb.ToString()); } private static string GetLongestWord(string[] words) { var longestWord = (from w in words orderby w.Length descending select w).First(); Console.WriteLine($"Task 1 -- The longest word is {longestWord}."); return longestWord; } // An http request performed synchronously for simplicity. static string[] CreateWordArray(string uri) { Console.WriteLine($"Retrieving from {uri}"); // Download a web page the easy way. string s = new WebClient().DownloadString(uri); // Separate string into an array of words, removing some common punctuation. return s.Split( new char[] { ' ', '\u000A', ',', '.', ';', ':', '-', '_', '/' }, StringSplitOptions.RemoveEmptyEntries); } #endregion } } // The example displays output like the following: // Retrieving from http://www.gutenberg.org/files/54700/54700-0.txt // Begin first task... // Begin second task... // Begin third task... // Task 2 -- The most common words are: // Oblomov // himself // Schtoltz // Gutenberg // Project // another // thought // Oblomov's // nothing // replied // // Task 1 -- The longest word is incomprehensible. // Task 3 -- The word "sleep" occurs 57 times. // Returned from Parallel.Invoke // Press any key to exit
-------------------------------------------------------顯式建立和執行任務--------------------------------------------------------------
不返回值的任務由 System.Threading.Tasks.Task 類表示。 返回值的任務由 System.Threading.Tasks.Task<TResult> 類表示,該類從 Task 繼承。 任務物件處理基礎結構詳細資訊,並提供可在任務的整個生存期內從呼叫執行緒訪問的方法和屬性。 例如,可以隨時訪問任務的 Status 屬性,以確定它是已開始執行、已完成執行、已取消還是引發了異常。 狀態由 TaskStatus 列舉表示。
在建立任務時,你賦予它一個使用者委託,該委託封裝該任務將執行的程式碼。 該委託可以表示為命名的委託、匿名方法或 lambda 表示式。 lambda 表示式可以包含對命名方法的呼叫,如下面的示例所示。 請注意,該示例包含對 Task.Wait 方法的呼叫,以確保任務在控制檯模式應用程式結束之前完成執行。
1.Task建構函式
using System; using System.Threading; using System.Threading.Tasks; public class Example { public static void Main() { Thread.CurrentThread.Name = "Main"; // Create a task and supply a user delegate by using a lambda expression. Task taskA = new Task( () => Console.WriteLine("Hello from taskA.")); // Start the task. taskA.Start(); // Output a message from the calling thread. Console.WriteLine("Hello from thread '{0}'.", Thread.CurrentThread.Name); taskA.Wait(); } } // The example displays output like the following: // Hello from thread 'Main'. // Hello from taskA.View Code
2.Task.Run啟動任務
using System; using System.Threading; using System.Threading.Tasks; public class Example { public static void Main() { Thread.CurrentThread.Name = "Main"; // Define and run the task. Task taskA = Task.Run( () => Console.WriteLine("Hello from taskA.")); // Output a message from the calling thread. Console.WriteLine("Hello from thread '{0}'.", Thread.CurrentThread.Name); taskA.Wait(); } } // The example displays output like the following: // Hello from thread 'Main'. // Hello from taskA.View Code
3.Task.Factory.StartNew
using System; using System.Threading.Tasks; public class Example { public static void Main() { Task<Double>[] taskArray = { Task<Double>.Factory.StartNew(() => DoComputation(1.0)), Task<Double>.Factory.StartNew(() => DoComputation(100.0)), Task<Double>.Factory.StartNew(() => DoComputation(1000.0)) }; var results = new Double[taskArray.Length]; Double sum = 0; for (int i = 0; i < taskArray.Length; i++) { results[i] = taskArray[i].Result; Console.Write("{0:N1} {1}", results[i], i == taskArray.Length - 1 ? "= " : "+ "); sum += results[i]; } Console.WriteLine("{0:N1}", sum); } private static Double DoComputation(Double start) { Double sum = 0; for (var value = start; value <= start + 10; value += .1) sum += value; return sum; } } // The example displays the following output: // 606.0 + 10,605.0 + 100,495.0 = 111,706.0View Code
-------------------------------------------------------建立任務延續--------------------------------------------------------------
使用 Task.ContinueWith 和 Task<TResult>.ContinueWith 方法,可以指定要在先行任務完成時啟動的任務。 延續任務的委託已傳遞了對先行任務的引用,因此它可以檢查先行任務的狀態,並通過檢索 Task<TResult>.Result 屬性的值將先行任務的輸出用作延續任務的輸入。
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); } } // The example displays output similar to the following: // N=100, Total = 110,081,653,682, Mean = 1,100,816,536.82View Code
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); } } // The example displays output similar to the following: // N=100, Total = 110,081,653,682, Mean = 1,100,816,536.82View Code