Task
Posted 【我是谁】
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Task相关的知识,希望对你有一定的参考价值。
一、Task是任务,不是线程,但是执行的时候是需要线程;任务跟线程不是一对一的关系,比如开3个任务并不是说会开3个线程
在上一篇并行编程_Parallel文章中,反编译看了下源码Parallel.Invoke,会创建与调用的action[]数目一致的System.Threading.Tasks.Task的实例;Parallel.For、Parallel.ForEach的循环迭代的并行执行,也会创建Task实例
对于构造函数,属性,方法介绍看微软这篇msdn文档:https://msdn.microsoft.com/zh-cn/library/system.threading.tasks.task(v=vs.110).aspx
二、Task示例
1.0 创建和执行任务
1 #region 创建和执行任务 2 // Task.Run 3 Task task = Task.Run(() => 4 { 5 // Just loop. 6 int ctr = 0; 7 for (ctr = 0; ctr <= 1000000; ctr++) { } 8 Console.WriteLine("Finished {0} loop iterations", ctr); 9 }); 10 Console.WriteLine("可能接着执行到这儿"); 11 task.Wait(); 12 Console.ReadKey(); 13 14 15 //Task.Factory.StartNew 16 Task task = Task.Factory.StartNew(() => 17 { 18 // Just loop. 19 int ctr = 0; 20 for (ctr = 0; ctr <= 1000000; ctr++){ } 21 Console.WriteLine("Finished {0} loop iterations",ctr); 22 }); 23 task.Wait(); 24 Console.ReadKey(); 25 #endregion 创建和执行任务
2.0等待一个或多个任务完成,还有 ContinueWhenAll 方法等待一组方法全部完成在继续工作;
1 #region 等待一个或多个任务完成 2 //1.0Task.Wait 3 Task taskA = Task.Run(() => { Thread.Sleep(2000); }); 4 Console.WriteLine("taskA Status: {0}", taskA.Status);//WaitingToRun 5 try 6 { 7 taskA.Wait(); 8 Console.WriteLine("taskA Status: {0}", taskA.Status);//RanToCompletion 9 } 10 catch (AggregateException) 11 { 12 Console.WriteLine("Exception in taskA."); 13 14 } 15 Console.ReadKey(); 16 17 18 19 //2.0 Task.Wait(1000) 20 Task taskA = Task.Run(() => { Thread.Sleep(3000);}); 21 try 22 { 23 taskA.Wait(1000); // Wait for 1 second.main thread continue 24 bool completed = taskA.IsCompleted;//false 25 Console.WriteLine("taskA Status: {0}", taskA.Status); 26 if (!completed) 27 { 28 Console.WriteLine("Time out before task A completed."); 29 } 30 } 31 catch (AggregateException) 32 { 33 Console.WriteLine("Exception in taskA."); 34 35 } 36 37 38 //3.0Task.WaitAny,Task.WaitAll 39 var tasks = new Task[3]; 40 var rnd = new Random(); 41 for (int i = 0; i < 3; i++) 42 { 43 tasks[i] = Task.Run(() => { Thread.Sleep(rnd.Next(500, 3000)); }); 44 } 45 try 46 { 47 //等待哪个先完成就返回哪个任务的索引; 48 int index = Task.WaitAny(tasks); 49 Console.WriteLine("Task #{0} completed first.\\n", tasks[index].Id); //Task #1 completed first. 50 Console.WriteLine("Status of all tasks:"); 51 foreach (var t in tasks) 52 { 53 //Task #3: Running 54 //Task #4: Running 55 //Task #1: RanToCompletion 56 Console.WriteLine(" Task #{0}: {1}", t.Id, t.Status); 57 } 58 Task.WaitAll(tasks);//等待所有任务完成 59 foreach (var t in tasks) 60 { 61 //Task #3: RanToCompletion 62 //Task #4: RanToCompletion 63 //Task #1: RanToCompletion 64 Console.WriteLine(" Task #{0}: {1}", t.Id, t.Status); 65 } 66 } 67 catch (AggregateException) 68 { 69 Console.WriteLine("An exception occurred."); 70 } 71 Console.ReadKey(); 72 73 74 75 76 #endregion
3.0 异常处理示例, 参考:https://msdn.microsoft.com/zh-cn/library/dd997415(v=vs.110).aspx,try-catch,ContinueWith==>IsFaulted
示例:其它可查看第二篇的TaskCompletionSource,有些:http://www.cnblogs.com/entclark/p/8047323.html
1 // Create a cancellation token and cancel it. 2 var source1 = new CancellationTokenSource(); 3 var token1 = source1.Token; 4 source1.Cancel(); 5 // Create a cancellation token for later cancellation. 6 var source2 = new CancellationTokenSource(); 7 var token2 = source2.Token; 8 9 // Create a series of tasks that will complete, be cancelled, timeout, or throw an exception. 10 Task[] tasks = new Task[12]; 11 for (int i = 0; i < 12; i++) 12 { 13 switch (i % 4) 14 { 15 // Task should run to completion. 16 case 0: 17 tasks[i] = Task.Run(() => Thread.Sleep(2000)); 18 break; 19 // Task should be set to canceled state. 20 case 1: 21 tasks[i] = Task.Run(() => Thread.Sleep(2000), 22 token1); 23 break; 24 25 case 2: 26 // Task should throw an exception. 27 tasks[i] = Task.Run(() => { throw new NotSupportedException(); }); 28 break; 29 30 case 3: 31 // Task should examine cancellation token. 32 tasks[i] = Task.Run(() => 33 { 34 Thread.Sleep(2000); 35 if (token2.IsCancellationRequested) 36 token2.ThrowIfCancellationRequested(); 37 Thread.Sleep(500); 38 }, token2); 39 break; 40 } 41 } 42 Thread.Sleep(250); 43 source2.Cancel(); 44 45 try 46 { 47 Task.WaitAll(tasks); 48 } 49 catch (AggregateException ae)//一般使用累加异常,不用出现第一个异常就跳到这里面,影响其他任务继续运行 50 { 51 Console.WriteLine("One or more exceptions occurred:"); 52 foreach (var ex in ae.InnerExceptions) 53 Console.WriteLine(" {0}: {1}", ex.GetType().Name, ex.Message); 54 } 55 56 Console.WriteLine("\\nStatus of tasks:"); 57 foreach (var t in tasks) 58 { 59 Console.WriteLine(" Task #{0}: {1}", t.Id, t.Status); 60 if (t.Exception != null) 61 { 62 foreach (var ex in t.Exception.InnerExceptions) 63 Console.WriteLine(" {0}: {1}", ex.GetType().Name, 64 ex.Message); 65 } 66 } 67 Console.ReadKey();
4.0 任务和区域性
1 //下面的示例创建并执行四项任务。 三个任务执行 Action< T > 委托名为 action, ,这样便可以接受类型的参数 Object。 2 //任务 t1 实例化时通过调用任务类构造函数,但通过调用会启动其 Start() 方法仅在任务后的 t2 已启动。 3 //任务 t2 会实例化并通过调用单个方法调用中启动 TaskFactory.StartNew(Action<Object>, Object) 方法。 4 //任务 t3 会实例化并通过调用单个方法调用中启动 Run(Action) 方法。 5 //任务 t4 上同步执行主线程通过调用 RunSynchronously() 方法。 6 Action <object> action = (object obj) => 7 { 8 Console.WriteLine("Task={0}, obj={1}, Thread={2}", 9 Task.CurrentId, obj, 10 Thread.CurrentThread.ManagedThreadId); 11 }; 12 13 // Create a task but do not start it. 14 Task t1 = new Task(action, "alpha"); 15 16 // Construct a started task 17 Task t2 = Task.Factory.StartNew(action, "beta"); 18 // Block the main thread to demonstate that t2 is executing 19 t2.Wait(); 20 21 // Launch t1 22 t1.Start(); 23 Console.WriteLine("t1 has been launched. (Main Thread={0})", 24 Thread.CurrentThread.ManagedThreadId); 25 // Wait for the task to finish. 26 t1.Wait(); 27 28 // Construct a started task using Task.Run. 29 String taskData = "delta"; 30 Task t3 = Task.Run(() => { 31 Console.WriteLine("Task={0}, obj={1}, Thread={2}", 32 Task.CurrentId, taskData, 33 Thread.CurrentThread.ManagedThreadId); 34 }); 35 // Wait for the task to finish. 36 t3.Wait(); 37 38 // Construct an unstarted task 39 Task t4 = new Task(action, "gamma"); 40 // Run it synchronously 41 t4.RunSynchronously(); 42 // Although the task was run synchronously, it is a good practice 43 // to wait for it in the event exceptions were thrown by the task. 44 t4.Wait(); 45 Console.ReadKey();
三、Task<TResult>示例,一个可以返回值的异步操作。获取结果的时候必须等待操作完成,t.Result
//备注:Task<TResult> 类的表示单个操作通常返回一个值,并以异步方式执行。 Task<TResult> 对象是一种.NET Framework 4 中引入的第一个主要的组件。 //因为由执行工作 Task<TResult> 对象通常以异步方式执行在线程池线程上而不是以同步方式在主应用程序线程,您可以使用 Status 属性,以及 IsCanceled, //IsCompleted, ,和 IsFaulted 属性,以确定任务的状态。 大多数情况下,lambda 表达式用于指定的任务是执行的工作。 //Task<TResult> 可以多种方式创建实例。 最常用的方法,是调用静态 Task.Run<TResult>(Func<TResult>) 或 Task.Run<TResult>(Func<TResult>, CancellationToken) //方法。 这些方法提供简单的方法来启动任务,通过使用默认值,而无需获取其他参数。
1 var t = Task.Run(() => 2 { 3 // Just loop. 4 int max = 1000000; 5 int ctr = 0; 6 for (ctr = 0; ctr <= max; ctr++) 7 { 8 if (ctr == max / 2 && DateTime.Now.Hour <= 12) 9 { 10 ctr++; 11 break; 12 } 13 } 14 Thread.Sleep(2000); 15 return ctr; 16 17 }); 18 //主线程继续 19 Console.WriteLine("...."); 20 //必须等待输出结果,阻塞主线程 21 Console.WriteLine("Finished {0:N0} iterations.",t.Result); 22 //主线程继续 23 Console.WriteLine("...."); 24 Console.ReadKey(); 25 26 Task
1 var t = Task<int>.Factory.StartNew(() => 2 { 3 // Just loop. 4 int max = 1000000; 5 int ctr = 0; 6 for (ctr = 0; ctr <= max; ctr++) 7 { 8 if (ctr == max / 2 && DateTime.Now.Hour <= 12) 9 { 10 ctr++; 11 break; 12 } 13 } 14 Thread.Sleep(2000); 15 return ctr; 16 }); 17 //主线程继续 18 Console.WriteLine("...."); 19 //必须等待输出结果,阻塞主线程 20 Console.WriteLine("Finished {0:N0} iterations.", t.Result); 21 //主线程继续 22 Console.WriteLine("...."); 23 Console.ReadKey(); 24 25 TaskFactory
1 //一次使用的方法,使用匿名方法或者委托或者lambda代替,多次只在本方法体中使用就用委托 2 Func<double, double> doComputation = (start) => 3 { 4 Double sum = 0; 5 for (var value = start; value <= start + 10; value += .1) 6 sum += value; 7 8 return sum; 9 }; 10 Task<double>[] taskArray = 11 { 12 Task<double>.Factory.StartNew(() => doComputation(1.0)), 13 Task<double>.Factory.StartNew(() => doComputation(100.0)), 14 Task<double>.Factory.StartNew(() => doComputation(1000.0)) 15 }; 16 var results = new double[taskArray.Length]; 17 double sum2 = 0.0; 18 for (int i = 0; i < taskArray.Length; i++) 19 { 20 results[i] = taskArray[i].Result; 21 Console.Write("{0:N1} {1}", results[i], 22 i == taskArray.Length - 1 ? "= " : "+ "); 23 sum2 += results[i]; 24 } 25 Console.WriteLine("{0:N1}", sum2); 26 Console.ReadKey();
四、创建任务延续
//使用 Task.ContinueWith 和 Task<TResult>.ContinueWith 方法可以指定在先行任务完成时要启动的任务。 延续任务的委托已传递了对先行任务的引用,因此它可以检查先行任务的状态,
并通过检索 Task<TResult>.Result 属性的值将先行任务的输出用作延续任务的输入。可以直接在任务上ContinueWith或者用任务实例ContinueWith:
1 var displayData = Task.Factory.StartNew(() => 2 { 3 Random rnd = new Random(); 4 int[] values = new int[100]; 5 for (int ctr = 0; ctr <= values.GetUpperBound(0); ctr++) 6 values[ctr] = rnd.Next(); 7 return values; 8 }).ContinueWith((x) => 9 { 10 int n = x.Result.Length; 11 long sum = 0; 12 double mean; 13 14 for (int ctr = 0; ctr <= x.Result.GetUpperBound(0); ctr++) 15 sum += x.Result[ctr]; 16 17 mean = sum / (double)n; 18 return Tuple.Create(n, sum, mean); 19 }).ContinueWith((x) => 20 { 21 return String.Format("N={0:N0}, Total = {1:N0}, Mean = {2:N2}", 22 x.Result.Item1, x.Result.Item2, 23 x.Result.Item3); 24 }); 25 Console.WriteLine(displayData.Result);
//创建一个任务,在数组中的任务之一通过调用完成后开始 ContinueWhenAny 方法。 //创建一个任务,在数组中的所有任务已都完成通过调用开始 ContinueWhenAll 方法。比较常用
Task<string[]>[] tasks = new Task<string[]>[2]; string docsDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); tasks[0] = Task<string[]>.Factory.StartNew(() => Directory.GetFiles(docsDirectory)); tasks[1] = Task<string[]>.Factory.StartNew(() =&以上是关于Task的主要内容,如果未能解决你的问题,请参考以下文章