-------------------------------------------------------隐式创建和运行任务--------------------------------------------------------------
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; using 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 array Parallel.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.
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.
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.0
-------------------------------------------------------创建任务延续--------------------------------------------------------------
使用 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.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); } } // The example displays output similar to the following: // N=100, Total = 110,081,653,682, Mean = 1,100,816,536.82