Task、TaskFactory

首次构造一个Task对象时,其的状态是Created。以后当任务启动时,其的状态变成WaitingToRun。Task在一个线程上运行时,其的状态变成Running。任务停止运行,并等待其的任何子任务时,状态变成WaitingForChildrenToComplete。任务完全结束时,它进入以下三个状态之一:RanToCompletion,Canceled或者Faulted。一个Task<TResult>运行完成时,可通过Task<TResult>的Result属性来查询任务的结果,一个Task或者Task<TResult>出错时,可以查询Task的Exception属性来获得任务抛出的未处理的异常,该属性总是返回一个AggregateException对象,他包含所有未处理的异常。

Task提供了几个只读的Boolean属性,IsCanceled,IsFaulted,IsCompleted。注意,当Task处于RanToCompleted,Canceled或者Faulted状态时,IsCompleted返回True。为了判断一个Task是否成功完成,最简单的方法是

 if(task.Status == TaskStatus.RanToCompletion)

如果想要得到返回的结果,需使用Task<T>

 static void Main(string[] args)
        {
            Task<int> task = new Task<int>(o => Sum((int)o), 100);
            task.Start();
            task.Wait();
            if(task.Status == TaskStatus.RanToCompletion){
                 Console.WriteLine(task.Result);
            }
               
            Console.ReadKey();
        }
        static int Sum( int n ) {
            int sum = 0;
            for(int i = 0; i <= n ; i++){
                //token.ThrowIfCancellationRequested();
                sum += i;
                //Thread.Sleep(2000);
            } 
            return sum;
        }

一个任务结束时启动另外一个任务:

static void Main(string[] args)
        {
            Task<int> task = new Task<int>(o => Sum((int)o), 100);
            task.Start();
            Task tk = task.ContinueWith(ts => Console.WriteLine(ts.Result));
            Console.ReadKey();
        }
        static int Sum( int n ) {
            int sum = 0;
            for(int i = 0; i <= n ; i++){
                //token.ThrowIfCancellationRequested();
                sum += i;
                //Thread.Sleep(2000);
            } 
            return sum;
        }

父任务里面启动子任务

 static void Main(string[] args)
        {
            Task<int[]> parent = new Task<int[]>(() =>
            {
                var result = new int[3];
                new Task(() => result[0] = Sum(1000), TaskCreationOptions.AttachedToParent).Start();
                new Task(() => result[1] = Sum(2000), TaskCreationOptions.AttachedToParent).Start();
                new Task(() => result[2] = Sum(3000), TaskCreationOptions.AttachedToParent).Start();
                return result;
            });
            var sum = parent.ContinueWith(parentTsk => Array.ForEach(parentTsk.Result, Console.WriteLine));
            parent.Start();
            Console.ReadKey();
        }

TaskFactory[转载]http://blog.csdn.net/chifuqi/article/details/7537423  

 

  有时候 需创建一组具有相同状态的Task对象, 可使用System.Threading.Tasks命名空间中TaskFactory<TResult>类型和TaskFactory类型,两者均派生自System.Object。所有任务可共享的属性有:CancellationToken,TaskScheduler, TaskCreationgOption, TaskContinuation.

 

 对此有以下测试目的:

 

1. 任务工厂内各任务是否异步执行

 

2. CancellationTokeSource类对协作式的影响

 

3. 父子任务的影响关系

 

4. 任务错误信息的捕获

 

5. ContinueWith 与 ContinueWhenAll的使用

  1. using System;  
  2. using System.Threading;  
  3. using System.Runtime.Remoting.Messaging;  
  4. using System.Threading.Tasks;  
  5. using System.Linq;  
  6. using System.Text;  
  7.   
  8. namespace ConsoleApplication1  
  9. {  
  10.     class Program  
  11.     {  
  12.         static void Main(string[] args)  
  13.         {  
  14.             Task parent = new Task(() =>  
  15.             {  
  16.                 var cts = new CancellationTokenSource();  
  17.                 var tf = new TaskFactory(cts.Token, TaskCreationOptions.AttachedToParent, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);  
  18.   
  19.                 var childrenTasks = new[]  
  20.                 {  
  21.                     tf.StartNew(() => sum(cts.Token,500)),  
  22.                     tf.StartNew(() => sum(cts.Token, 100)),  
  23.                     tf.StartNew(() => sum(cts.Token, 1000)),  
  24.                     tf.StartNew(() => sum(cts.Token, 200)),  
  25.                     tf.StartNew(() => sum(cts.Token, 3000)),  
  26.                     tf.StartNew(() => sum(cts.Token, 400)),  
  27.                     tf.StartNew(() => sum(cts.Token, 800)),  
  28.                      
  29.                 };  
  30.   
  31.   
  32.                 for (int task = 0; task < childrenTasks.Length; task++)  
  33.                     childrenTasks[task].ContinueWith(t => cts.Cancel(), TaskContinuationOptions.OnlyOnFaulted);  
  34.   
  35.                 tf.ContinueWhenAll(childrenTasks,  
  36.                     completedTasks => completedTasks.Where(  
  37.                         t => !t.IsFaulted && !t.IsCanceled).Max(t => t.Result), CancellationToken.None).ContinueWith(  
  38.                         t => Console.WriteLine("The max is: " + t.Result),  
  39.                             TaskContinuationOptions.ExecuteSynchronously);  
  40.             });  
  41.   
  42.             parent.ContinueWith(p =>  
  43.             {  
  44.                 StringBuilder sb = new StringBuilder("The following exception(s) occurred: " + Environment.NewLine);  
  45.   
  46.                 if (p.Exception != null)  
  47.                 {  
  48.                     foreach (var e in p.Exception.Flatten().InnerExceptions)  
  49.                         sb.AppendLine(" " + e.GetType().ToString());  
  50.                 }  
  51.   
  52.                 Console.WriteLine(sb.ToString());  
  53.             }, TaskContinuationOptions.OnlyOnFaulted);  
  54.   
  55.   
  56.             parent.Start();  
  57.   
  58.             Console.ReadKey();  
  59.         }  
  1.         private static int sum(CancellationToken token, int n)  
  2.         {  
  3.             int sum = 0;  
  4.   
  5.             int tmp = n;  
  6.   
  7.             Console.WriteLine();  
  8.             Console.WriteLine(n);  
  9.   
  10.             Thread.Sleep(1000);  
  11.             
  12.                 for (; n > 0; n--)  
  13.                 {  
  14.                     if (token.IsCancellationRequested)  
  15.                     {  
  16.                         Console.WriteLine("\nCount is cancelled");  
  17.                         break;  
  18.                     }  
  19.   
  20.                     checked { sum += n; }  
  21.                     Console.Write(" n" + n.ToString());  
  22.                 }  
  23.   
  24.                 Console.WriteLine("\n" + tmp.ToString() + "End!");  
  25.             return sum;  
  26.         }  

 

分析:

 

1. 代码分为两部分 第二部分用于计算求和,且随时根据token值决定是否结束当前任务;第一部分创建父子线程

 

2. 父线程parent下利用TaskFactory创建若干同属性线程,均采用默认任务调度方式

 

3. for循环通知所有线程,如果一个线程faulted其余线程均停止工作。

 

childrenTasks[task].ContinueWith(t => cts.Cancel(), TaskContinuationOptions.OnlyOnFaulted);

 

本身便是个任务,只是这个任务只有满足条件TaskContinuationOptions.OnlyOnFaulted才会执行Action:cts.Cancel()。

 

4. 当childrenTasks所有任务完成后,取出没故障的(!t.IsFaulted)并不被取消的(!t.IsCanceled)的所有任务的最大值,并打印到屏幕上来。 注意之所以调用CancellationToken.None是因为tf.ContinueWhenAll仍属于parent的子任务,会受到cts.Token影响,所以通过覆盖CancellationToken.None以达到一直显示的目的。

 

5 parent在所有子任务的sum计算完成后(而不等待tf.ContinueWhenAll(...)执行完成)显示错误信息。

 

 

 

可得到以下结论:

 

1. 如下图: 任务工厂内各个任务异步执行;parent.ContinueWith与tf.ContinueWhenAll无直接关系。 

 


 

2. 更改代码为

 
  1. var childrenTasks = new[]  
  2. {  
  3.     tf.StartNew(() => sum(cts.Token,500)),  
  4.     tf.StartNew(() => sum(cts.Token, 100)),  
  5.     tf.StartNew(() => sum(cts.Token, Int32.MaxValue)),  
  6.     tf.StartNew(() => sum(cts.Token, 200)),  
  7.     tf.StartNew(() => sum(cts.Token, 3000)),  
  8.     tf.StartNew(() => sum(cts.Token, 400)),  
  9.     tf.StartNew(() => sum(cts.Token, 800)),  
  10.      
  11. };  

可得到

 


 

从而看出,当某一任务故障后导致cts.Cancel()执行;因此有两个任务(计数为200和3000)被终结.

 

3.推测:(不知是否正确)

 

父任务的结束标志是所有子任务完成,但不包括子任务所启动的任务。

 

 

 

 

 

 

 

 

 

 

 

posted @ 2013-01-08 09:52  _10Buns  阅读(1175)  评论(0)    收藏  举报