.NET 并行(多核)编程系列之六 Task基础部分完结篇

简介: 原文:.NET 并行(多核)编程系列之六 Task基础部分完结篇.NET 并行(多核)编程系列之六 Task基础部分完结篇   前言:之前的文章介绍了了并行编程的一些基本的,也注重的讲述了Task的一些使用方法,本篇很短,将会结束Task的基础知识的介绍。
原文: .NET 并行(多核)编程系列之六 Task基础部分完结篇

.NET 并行(多核)编程系列之六 Task基础部分完结篇

  前言:之前的文章介绍了了并行编程的一些基本的,也注重的讲述了Task的一些使用方法,本篇很短,将会结束Task的基础知识的介绍。

 

  本篇的主要议题如下:

  1.       获取Task的状态

  2.       执行晚加载的Task(Lazily Task)

  3.       常见问题的解决方案

 

  系列文章链接:

  .NET 4 并行(多核)编程系列之一入门介绍

  .NET 4 并行(多核)编程系列之二 从Task开始 

  .NET 4 并行(多核)编程系列之三 从Task的取消 

  .NET 4 并行(多核)编程系列之四 Task的休眠 

  .NET 并行(多核)编程系列之五 Task执行和异常处理 

  .NET 并行(多核)编程系列之六 Task基础部分完结篇 

  .NET 并行(多核)编程系列之七 共享数据问题和解决概述

 

  1.       获取Task的状态

        在.NET并行编程还有一个已经标准化的操作就是可以获取task的状态,通过Task.Status属性来得到的,这个属性返回一个System.Threading.Tasks.TaskStatus的枚举值。

如下:

       Created:表明task已经被初始化了,但是还没有加入到Scheduler中。

       WatingForActivationtask正在等待被加入到Scheduler中。

 WaitingToRun:已经被加入到了Scheduler,等待执行。

       Runningtask正在运行

       WaitingForChildrenToComplete:表明父task正在等待子task运行结束。

       RanToCompletion:表明task已经执行完了,但是还没有被cancel,而且也这个task也没有抛出异常。

       Canceled:表明task已经被cancel了。(大家可以参看之前讲述取消task的文章)

       Faulted:表明task在运行的时候已经抛出了异常。

 

  2.       执行晚加载的Task(Lazily Task)

晚加载,或者又名延迟初始化,主要的好处就是避免不必要的系统开销。在并行编程中,可以联合使用Lazy变量和Task<>.Factory.StartNew()做到这点。(Lazy变量时.NET 4中的一个新特性,这里大家不用知道Lazy的具体细节)

       Lazy变量只有在用到的时候才会被初始化。所以我们可以把Lazy变量和task的创建结合:只有这个task要被执行的时候才去初始化。

       下面还是通过例子来讲解: 

 

img_405b18b4b6584ae338e0f6ecaf736533.gif 代码
   static   void  Main( string [] args)
        {
            
//  define the function
            Func < string >  taskBody  =   new  Func < string > (()  =>
            {
                Console.WriteLine(
" Task body working... " );
                
return   " Task Result " ;
            });

            
//  create the lazy variable
            Lazy < Task < string >>  lazyData  =   new  Lazy < Task < string >> (()  =>
            Task
< string > .Factory.StartNew(taskBody));

            Console.WriteLine(
" Calling lazy variable " );
            Console.WriteLine(
" Result from task: {0} " , lazyData.Value.Result);

            
//  do the same thing in a single statement
            Lazy < Task < string >>  lazyData2  =   new  Lazy < Task < string >> (
            () 
=>  Task < string > .Factory.StartNew(()  =>
            {
                Console.WriteLine(
" Task body working... " );
                
return   " Task Result " ;
            }));

            Console.WriteLine(
" Calling second lazy variable " );
            Console.WriteLine(
" Result from task: {0} " , lazyData2.Value.Result);

            
//  wait for input before exiting
            Console.WriteLine( " Main method complete. Press enter to finish. " );
            Console.ReadLine();
        }

 

      

  首先我们回想一下,在之前的系列文章中我们是怎么定义一个task的:直接new,或者通过taskfactory来创建,因为创建task的代码是在main函数中的,所以只要new了一个task,那么这个task就被初始化。现在如果用了Lazytask,那么现在我们初始化的就是那个Lazy变量了,而没有初始化task(初始化Lazy变量的开销小于初始化task),只有当调用了lazyData.Value时,Lazy变量中包含的那个task才会初始化。(这里欢迎大家提出自己的理解) 

 

  3.       常见问题的解决方案

a.       Task 死锁

描述:如果有两个或者多个task(简称TaskA)等待其他的taskTaskB)执行完成才开始执行,但是TaskB也在等待TaskA执行完成才开始执行,这样死锁就产生了。

 

解决方案:避免这个问题最好的方法就是:不要使的task来依赖其他的task。也就是说,最好不要你定义的task的执行体内包含其他的task

 

例子:在下面的例子中,有两个task,他们相互依赖:他们都要使用对方的执行结果。当主程序开始运行之后,两个task也开始运行,但是因为两个task已经死锁了,所以主程序就一直等待。

 

 

img_405b18b4b6584ae338e0f6ecaf736533.gif 代码
   static   void  Main( string [] args)
        {
            
//  define an array to hold the Tasks
            Task < int > [] tasks  =   new  Task < int > [ 2 ];

            
//  create and start the first task
            tasks[ 0 =  Task.Factory.StartNew(()  =>
            {
                
//  get the result of the other task,
                
//  add 100 to it and return it as the result
                 return  tasks[ 1 ].Result  +   100 ;
            });

            
//  create and start the second task
            tasks[ 1 =  Task.Factory.StartNew(()  =>
            {
                
//  get the result of the other task,
                
//  add 100 to it and return it as the result
                 return  tasks[ 1 ].Result  +   100 ;
            });


            
//  wait for the tasks to complete
            Task.WaitAll(tasks);

            
//  wait for input before exiting
            Console.WriteLine( " Main method complete. Press enter to finish. " );
            Console.ReadLine();
        }

 

 

   本篇就到这里了,很短,基础的部分就基本介绍完了,后面的文章就开始讲述应用。

   版权为小洋和博客园所有,转载请标明出处给作者。

   http://www.cnblogs.com/yanyangtian

 

 

 

 

 

 

 

 

 

 

 

 

 

 

目录
相关文章
|
4月前
|
算法 Java 调度
|
SQL .NET C#
.Net并行编程(一)-TPL之数据并行
前言 许多个人计算机和工作站都有多个CPU核心,可以同时执行多个线程。利用硬件的特性,使用并行化代码以在多个处理器之间分配工作。 应用场景 文件批量上传并行上传单个文件。也可以把一个文件拆成几段分开上传,加快上传速度。
1590 0
C#.NET使用Task,await,async,异步执行控件耗时事件(event),不阻塞UI线程和不跨线程执行UI更新,以及其他方式比较
原文:C#.NET使用Task,await,async,异步执行控件耗时事件(event),不阻塞UI线程和不跨线程执行UI更新,以及其他方式比较 使用Task,await,async,异步执行事件(event),不阻塞UI线程和不跨线程执行UI更新   使用Task,await,async 的异步模式 去执行事件(event) 解决不阻塞UI线程和不夸跨线程执行UI更新报错的最佳实践,附加几种其他方式比较 由于是Winform代码和其他原因,本文章只做代码截图演示,不做界面UI展示,当然所有代码都会在截图展示。
4785 0