[Multithreading]关于Task总结_.NET_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > .NET > [Multithreading]关于Task总结

[Multithreading]关于Task总结

 2013/7/17 16:14:17  YanZhiwei  博客园  我要评论(0)
  • 摘要:Task表示一个异步操作。Task实例可以用各种不同的方式创建。最常见的方法是使用任务类型的Factory属性检索可用来创建用于多个用途的任务的TaskFactory实例。Task类还提供了初始化任务但不计划执行任务的构造函数。出于性能方面的考虑,TaskFactory的StartNew方法应该是创建和计划计算任务的首选机制,但是对于创建和计划必须分开的情况,可以使用构造函数,然后可以使用任务的Start方法计划任务在稍后执行。对于返回值的操作,应使用Task<TResult>类
  • 标签:总结 thread

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

image

从任务中获取返回值


            #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

image

任务取消


        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();
        }

image

在Task被取消的时候,注册执行委托


        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();
        }

image

处理任务中的异常


    在任务执行过程中产生的未处理异常,任务会把它暂时隐藏起来,装进一个集合中。当我们调用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.");
        }
image

参考资料:

.NET 4.0 任务(Task)

.NET 4中的多线程编程之一:使用Task

簡介.NET 4.0的多工執行利器—Task

http://developer.51cto.com/art/201006/204843.htm

发表评论
用户名: 匿名