博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
(转)NET 4 并行(多核)编程系列之一 从Task开始
阅读量:4480 次
发布时间:2019-06-08

本文共 4374 字,大约阅读时间需要 14 分钟。

本篇文章的议题如下:

    1.Task基础介绍
    2.Task的创建

    3.获取Task的执行结果

  4. 补充细节

 

 

    1.Task基础介绍

 

    首先我们还是来看看一段简单的代码:

   

    这里展示的只是一段简单的代码,不能显示出并行编程的特点。但是我们还是从最基本的开始看,慢慢进入深一点的话题。

    
    如果你曾经用过.NET 中的多线程编程,比较一下,就会发现:这段代码虽然在底层还是使用了多线程,但是写法上却简化了很多,一行代码就实现了一个并行编程。
    
    下面我们就从Task类开始谈。
    Task类是Task Programming Library(TPL)中最核心的一个类,下面我将会像大家展示如何使用一些方法来创建不同类型的Task,
取消Task,等待Task执行完成,获取Task执行后的结果和对异常进行处理。
    在开始讨论之前,我们首先快速的看看之前的代码:
  
    这个命名空间将会是我们之后在讲述并行编程经常使用的一个。这个空间包含了很多与并行编程有关的类。
    还有一个要你使用的命名空间是:System.Threading,大家对这个应该比较熟悉了,之前的多线程编程常常使用到,这个空间下包含了一些在并行编程中用来协调数据的一些类。
    上面代码中,最主要的代码如下:
   

  Task.Factory.StartNew(() 
=>
            {
                Console.WriteLine(
"
Hello World
"
);
            });

 

    我们用静态方法:Task.Factory.StartNew()来创建了一个最简单的Task--在屏幕上打印一句话。这段代码确实简单,而且都没有任何输入和需要返回的结果。
    下面我们就正式进入议题:
    2.Task的创建   

  

    如果只是创建一个简单的Task,我们只要为该Task提供一个执行体就行了,执行体可以是一个委托delegate或者action。我们之前展示的那段代码就是采用了lambda表达式来作为Task的执行体。
    2.1 创建一个简单的Task

 

    为了执行一个简单的Task,一般进行以下步骤:

    首先,要创建一个Task类的实例,
    然后,传入一个System.Action委托,这个委托中的方法就是这个Task运行时你要执行的方法,而且这个委托必须作为Task构造函数的一个参数传入。我们在传入委托作为参数的时候有多种方式:传入匿名委托,
Lambda表达式或者一个显示什么方法的委托。
    最后,调用Task实例的Start()方法来运行。
    
    当这个Task实例开始运行的时候,它就被传给了内部的一个task scheduler,这个scheduler负责把我们创建的task交给底下的线程去执行。
    下面就看看代码:
   

ContractedBlock.gif
ExpandedBlockStart.gif
代码
using
 System;
using
 System.Threading.Tasks;
namespace
 Listing_02
{
    
class
 Listing_02
    {
        
static
 
void
 Main(
string
[] args)
        {
            
//
 use an Action delegate and a named method
            Task task1 
=
 
new
 Task(
new
 Action(printMessage));
            
//
 use a anonymous delegate
            Task task2 
=
 
new
 Task(
delegate
            {
                printMessage();
            });
            
//
 use a lambda expression and a named method
            Task task3 
=
 
new
 Task(() 
=>
 printMessage());
            
//
 use a lambda expression and an anonymous method
            Task task4 
=
 
new
 Task(() 
=>
            {
                printMessage();
            });
            task1.Start();
            task2.Start();
            task3.Start();
            task4.Start();
            
//
 wait for input before exiting
            Console.WriteLine(
"
Main method complete. Press enter to finish.
"
);
            Console.ReadLine();
        }
        
static
 
void
 printMessage()
        {
            Console.WriteLine(
"
Hello World
"
);
        }
    }
}

 

    不知道大家注意到了没有,上面代码创建Task的方法和我们之前的第一段代码的创建Task的方法不同。在之前我们采用的是Task.Factory.StartNew()方法来创建的,这个方法创建Task并且开始运行Task,其实两端代码的结果是一样的,这里给出一点建议:如果这是想简单的创建一个Task,那么使用Factory.NewStart()来创建,很简便,如果像对所创建的Task附加更多的定制和设置特定的属性,那么还是得一步一步的按照我们说的那些步骤来。(详细的我们后续会介绍的)
    2.1 为创建的Task传入参数  

  

    我们之前提过,在创建Task的时候,我们在构造函数中传入了一个System.Action的委托,如果我们想要把一些参数传入到Task中,那么我 们可以传入System.Action<object>的委托,其中的那个object就是我们传入的参数。还是给大家举个例子:
   

ContractedBlock.gif
ExpandedBlockStart.gif
代码
using
 System;
using
 System.Threading.Tasks;
namespace
 Listing_04
{
    
class
 Listing_04
    {
        
static
 
void
 Main(
string
[] args)
        {
            
string
[] messages 
=
 { 
"
First task
"
"
Second task
"
,
"
Third task
"
"
Fourth task
"
 };
            
foreach
 (
string
 msg 
in
 messages)
            {
                Task myTask 
=
 
new
 Task(obj 
=>
 printMessage((
string
)obj), msg);
                myTask.Start();
            }
            
//
 wait for input before exiting
            Console.WriteLine(
"
Main method complete. Press enter to finish.
"
);
            Console.ReadLine();
        }
        
static
 
void
 printMessage(
string
 message)
        {
            Console.WriteLine(
"
Message: {0}
"
, message);
        }
    }
}

 

    

    注意:我们在传入参数后,必须把参数转换为它们原来的类型,然后再去调用相应的方法。例子中,因为System.Action对应的方法是printMessage()方法,而这个方法的要求的参数类型是string,所以要转换为string。
  想向Task传入参素,只能用System.Action<object>
    3.获取Task的执行结果
     

   如果要获取Task的结果,那么在创建Task的时候,就要采用Task<T>来实例化一个Task,其中的那个T就是task执行完成之后返回结果的类型。之后采用Task实例的Result属性就可以获取结果。

    代码显示如下:
    

ContractedBlock.gif
ExpandedBlockStart.gif
代码
 
static
 
void
 Main(
string
[] args)
        {
            
//
 create the task
            Task
<
int
>
 task1 
=
 
new
 Task
<
int
>
(() 
=>
            {
                
int
 sum 
=
 
0
;
                
for
 (
int
 i 
=
 
0
; i 
<
 
100
; i
++
)
                {
                    sum 
+=
 i;
                }
                
return
 sum;
            });
            
            task1.Start();
            
//
 write out the result
            Console.WriteLine(
"
Result 1: {0}
"
, task1.Result);
            
            Console.ReadLine();
        }

 

    只有在task执行完成之后,才能获取到Result的值。

    下面的代码展示了如何通过Task.Factory.StartNew<T>()创建一个Task,并且获取结果:
    

ContractedBlock.gif
ExpandedBlockStart.gif
代码
  
static
 
void
 Main(
string
[] args)
        {
            
//
 create the task
            Task
<
int
>
 task1 
=
 Task.Factory.StartNew
<
int
>
(() 
=>
            {
                
int
 sum 
=
 
0
;
                
for
 (
int
 i 
=
 
0
; i 
<
 
100
; i
++
)
                {
                    sum 
+=
 i;
                }
                
return
 sum;
            });
            
//
 write out the result
            Console.WriteLine(
"
Result 1: {0}
"
, task1.Result);
            
            Console.ReadLine();
        }

 

 

  4. 补充细节   

  在创建Task的时候,Task有很多的构造函数的重载,一个主要的重载就是传入TaskCreateOptions的枚举:     

    TaskCreateOptions.None:用默认的方式创建一个Task
    TaskCreateOptions.PreferFairness:请求scheduler尽量公平的执行Task(后续文章会将是,Task和线程一样,有优先级的)
    TaskCreateOptions.LongRunning:声明Task将会长时间的运行。
    TaskCreateOptions.AttachToParent:因为Task是可以嵌套的,所以这个枚举就是把一个子task附加到一个父task中。
    最后要提到的一点就是,我们可以在Task的执行体中用Task.CurrentId来返回Task的唯一表示ID(int)。如果在Task执行体外使用这个属性就会得到null。
    (熟悉WF的朋友,可以比较Task和WF的一些区别,因为我认为它们的设计思想很相近)
    今天就到这里了,多谢大家! 

 

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

  http://www.cnblogs.com/yanyangtian

转载于:https://www.cnblogs.com/GaryFeng/archive/2010/07/12/1775551.html

你可能感兴趣的文章
影响各类服务器性能瓶颈的因素【转】
查看>>
Jenkins
查看>>
jboss5 启动时报HsqlException:length must be specified in type definition:VARBINARY错误
查看>>
转载:让理科生沉默,让文科生流泪的综合题
查看>>
程序员7-2007-2010
查看>>
Android分类前言
查看>>
oracle中字符串的大小比较,字符串与数字的比较和运算
查看>>
2018年东北农业大学春季校赛 wyh的矩阵
查看>>
python网络爬虫与信息提取——4.Beautiful Soup库入门
查看>>
3145 汉诺塔游戏
查看>>
ASP.NET MVC做的微信WEBAPP中调用微信JSSDK扫一扫
查看>>
iOS SHA1加密实现方法
查看>>
List基本用法
查看>>
c# 正则表达式替换字符串中常见的特殊字符
查看>>
032 Longest Valid Parentheses 最长有效括号
查看>>
swiper 不同页面高度自适应
查看>>
使用Vundle管理Vim插件
查看>>
springboot整合mybatis分页插件PageHelper
查看>>
js正则的括号,类型,通配符
查看>>
BZOJ3786 星系探索 【Splay维护dfs序】*
查看>>