Task表示一个异步操作。Task 实例可以用各种不同的方式创建。 最常见的方法是使用任务类型的 Factory 属性检索可用来创建用于多个用途的任务的 TaskFactory 实例。
Task 类还提供了初始化任务但不计划执行任务的构造函数。 出于性能方面的考虑,TaskFactory 的 StartNew 方法应该是创建和计划计算任务的首选机制,但是对于创建和计划必须分开的情况,可以使用构造函数,然后可以使用任务的 Start 方法计划任务在稍后执行。 对于返回值的操作,应使用 Task<TResult>类。 ——MSDN
使用线程池有两个明显的缺点,那就是一旦把我们要执行的任务放进去后,什么时候执行完成,以及执行完成后需要返回值,我们都无法通过内置的方式而得知。由于任务(Task)的推出,使得我们对并行编程变得简单,而且不用关心底层是怎么实现的,由于比线程池更灵活,如果能掌握好Task,对于写出高效的并行代码非常有帮助。
class="csharpcode"> #region Task Task ts = new Task(() => Console.WriteLine("New Task Thread 1.")); ts.Start(); Task.Factory.StartNew(() => Console.WriteLine("New Task Thread 2.")); Console.WriteLine("Main Thread Exit."); #endregion
#region Task Return Value Task<string> _tReturnValue = Task.Factory.StartNew<string>(() => { Thread.Sleep(500); return string.Format("This is Task Return Value,{0}.", DateTime.Now); }); Stopwatch _watchTask = new Stopwatch(); _watchTask.Start(); //在访问_tReturnValue.Result的时候,.NET会保证此时Task的代码已经执行完毕,Result已经获得,否则该线程会阻塞,直到Result计算完毕。 Console.WriteLine(string.Format("Task Return Value :{0}.", _tReturnValue.Result)); Console.WriteLine(string.Format("Task Return Take Time:{0} ms.", _watchTask.Elapsed.TotalMilliseconds.ToString())); Task<int> _tCompute = Task.Factory.StartNew<int>(() => { int _nSum = 0; for (int i = 0; i < 1000; i++) _nSum += i; return _nSum; }); Console.WriteLine(string.Format("Compute value:{0}", _tCompute.Result)); #endregion
static void Main(string[] args) { CancellationTokenSource tsk = new CancellationTokenSource();//通知 CancellationToken,告知其应被取消。 CancellationToken token = tsk.Token;//传播有关应取消操作的通知。 Task task = new Task(() => { int i = 0; Console.WriteLine("Task start run."); while (true) { if (!tsk.IsCancellationRequested) { Console.WriteLine(string.Format("Task is run {0}.", i)); i++; } else { Console.WriteLine("Task is Cancel."); break; } } }, token); task.Start(); Thread.Sleep(20); tsk.Cancel(); Console.ReadLine(); }
static void Main(string[] args) { CancellationTokenSource tsk = new CancellationTokenSource();//通知 CancellationToken,告知其应被取消。 CancellationToken token = tsk.Token;//传播有关应取消操作的通知。 token.Register(() => { Console.WriteLine("Task is cancel."); });//注册委托,在Task被Cancel的时候执行。 Task task = new Task(() => { int i = 0; Console.WriteLine("Task start run."); while (true) { if (!tsk.IsCancellationRequested) { Console.WriteLine(string.Format("Task is run {0}.", i)); i++; } else { Console.WriteLine("Task is finished."); break; } } }, token); task.Start(); Thread.Sleep(10); tsk.Cancel(); Console.ReadLine(); }
在任务执行过程中产生的未处理异常,任务会把它暂时隐藏起来,装进一个集合中。当我们调用Wait方法或者Result属性时,任务会抛出一个AggregateException异常。我们可以通过调用AggregateException对象的只读属性InnerExceptions来得到一个ReadOnlyCollection<Exception>对象,它才是存储抛出异常的集合,它的第一个元素就是最初抛出的异常。同样的,AggregateException对象的InnerException属性也会返回最初抛出的异常。
值得重视的是,由于任务的隐藏机制的特点,一旦产生异常后,如果我们不调用相应的方法或者属性查看异常,我们也无法判断是否有异常产生(Task不会主动抛出异常)。当Task对象被GC回收时,Finalize方法会查检是否有未处理的异常,如果不幸刚才好有,则Finalize方法会将此AggregateException再度抛出,如果再不幸,我们没有捕获处理这个异常,则我们的程序会立即中止运行。如果发生这样的事情,会是多么大的灾难啊!
static void Main(string[] args) { Task tskThread1 = Task.Factory.StartNew(() => { Console.WriteLine("Task1 is runing."); throw new NullReferenceException(); }); Task tskThread2 = Task.Factory.StartNew(() => { Console.WriteLine("Task2 is runing."); throw new ArgumentNullException(); }); Task tskThread3 = Task.Factory.StartNew(() => { Console.WriteLine("Task3 is runing."); throw new Exception("Task exception test."); }); try { Task.WaitAll(tskThread1, tskThread2, tskThread3); } catch (AggregateException ex) { foreach (Exception e in ex.InnerExceptions) Console.WriteLine(e.GetType()); } Console.WriteLine("Main Thread Exit."); }
.NET 4.0 任务(Task)
.NET 4中的多线程编程之一:使用Task
簡介.NET 4.0的多工執行利器—Task
http://developer.51cto.com/art/201006/204843.htm