[转].NET 4 并行(多核)编程系列之二 从Task开始
本文转自:http://www.cnblogs.com/yanyangtian/archive/2010/05/22/1741379.html
前言:我们一步步的从简单的开始讲述,还是沿用我一直的方式:慢慢演化,步步为营。
本篇文章的议题如下: 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交给底下的线程去执行。 下面就看看代码:
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就是我们传入的参数。还是给大家举个例子:
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属性就可以获取结果。 代码显示如下:
static void Main(string[] args)
{
// create the task
Task<int> task1 = new Task<int>(() =>
{
int sum = ;
for (int i = ; i < ; 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,并且获取结果:
static void Main(string[] args)
{
// create the task
Task<int> task1 = Task.Factory.StartNew<int>(() =>
{
int sum = ;
for (int i = ; i < ; 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
[转].NET 4 并行(多核)编程系列之二 从Task开始的更多相关文章
- .NET 并行(多核)编程系列之七 共享数据问题和解决概述
原文:.NET 并行(多核)编程系列之七 共享数据问题和解决概述 .NET 并行(多核)编程系列之七 共享数据问题和解决概述 前言:之前的文章介绍了了并行编程的一些基础的知识,从本篇开始,将会讲述并行 ...
- .NET 并行(多核)编程系列之五 Task执行和异常处理
原文:.NET 并行(多核)编程系列之五 Task执行和异常处理 .NET 并行(多核)编程系列之五 Task执行和异常处理 前言:本篇主要讲述等待task执行完成. 本篇的议题如下: 1. 等待Ta ...
- .NET 并行(多核)编程系列之六 Task基础部分完结篇
原文:.NET 并行(多核)编程系列之六 Task基础部分完结篇 .NET 并行(多核)编程系列之六 Task基础部分完结篇 前言:之前的文章介绍了了并行编程的一些基本的,也注重的讲述了Task的一些 ...
- .NET 4 并行(多核)编程系列之二 从Task开始
原文:.NET 4 并行(多核)编程系列之二 从Task开始 .NET 4 并行(多核)编程系列之二 从Task开始 前言:我们一步步的从简单的开始讲述,还是沿用我一直的方式:慢慢演化,步步为营. ...
- paip.提升性能---并行多核编程哈的数据结构list,set,map
paip.提升性能---并行多核编程哈的数据结构list,set,map vector/copyonwritearraylist 都是线程安全的. 或者经过包装的list ::: collection ...
- C#多线程编程系列(二)- 线程基础
目录 C#多线程编程系列(二)- 线程基础 1.1 简介 1.2 创建线程 1.3 暂停线程 1.4 线程等待 1.5 终止线程 1.6 检测线程状态 1.7 线程优先级 1.8 前台线程和后台线程 ...
- Python GUI之tkinter窗口视窗教程大集合(看这篇就够了) JAVA日志的前世今生 .NET MVC采用SignalR更新在线用户数 C#多线程编程系列(五)- 使用任务并行库 C#多线程编程系列(三)- 线程同步 C#多线程编程系列(二)- 线程基础 C#多线程编程系列(一)- 简介
Python GUI之tkinter窗口视窗教程大集合(看这篇就够了) 一.前言 由于本篇文章较长,所以下面给出内容目录方便跳转阅读,当然也可以用博客页面最右侧的文章目录导航栏进行跳转查阅. 一.前言 ...
- 学习ASP.NET Core Razor 编程系列十二——在页面中增加校验
学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...
- TCP/IP网络编程系列之二(初级)
套接字类型与协议设置 我们先了解一下创建套接字的那个函数 int socket(int domain,int type,int protocol);成功时返回文件描述符,失败时返回-1.其中,doma ...
随机推荐
- gcc 头文件是用户应用程序和函数库之间的桥梁和纽带 功能的真正逻辑实现是以硬件层为基础
gcc GCC, the GNU Compiler Collection - GNU Project - Free Software Foundation (FSF) http://gcc.gnu.o ...
- dataTables-details 1.9
本文共四部分:官网 | 基本使用|遇到的问题|属性表 一:官方网站:[http://www.datatables.net/] 二:基本使用:[http://www.guoxk.com/node/jqu ...
- 一个基本的spring+mybatis所需要的包
spring+mybatis需要的包:org.springframework.spring-webmvc(spring框架DispatcherServlet需要,spring-webmvc会依赖spr ...
- GPS常见故障
当出现故障时,依据可能原因进行排查. 下表列举典型故障及调试方法 现象 root cause 检查 实验 GPS无法开启/无法搜星 软件配置错误 SW 相关配置(如GPIO等) 录制mobile ...
- 关于苹果iPhone手机对页面margin属性无效的解决方法一(如有错误,请留言批评)
这个问题,是在给商城网站底部footer设置margin属性的时候发现的,先把出现问题的截图发出来看一下 安卓手机,打开正常 iphone6 p 打开出现的问题(无视margin-bottom:6 ...
- [推荐]Silverlight 2 开发者海报
从Brad Abrams的Blog上看到了一张Silverlight 2开发者海报,非常酷,拿出来与大家分享. [JPG版本 5.8MB] [PNG版本 6.5MB] [TIF版本 19.9 MB] ...
- 【Maven】pom.xml(1)
在pom.xml加入: <build> <finalName>oauth2</finalName> <resources> <resource&g ...
- No tests found with test runner 'JUnit 3'
报异常:No tests found with test runner 'JUnit 3' 解决方案: 主要因为你当前建的JUnit类是3的版本,将该类备份,重新创建一个类. 1.右键目录New--O ...
- FTOUR2 - Free tour II
传送门 题目翻译的很清楚……似乎点分治的题题目描述都非常简洁. 还是那个操作,一条路径要么全部在一棵子树中,要么经过当前的重心,所以考虑点分治. 首先dfs求出重心的每一棵子树中,有i个黑点的最长路径 ...
- redhat 关机注销命令详解
一.注销,关机,重启 注销系统的logout命令 1,Logout 注销是登陆的相对操作,登陆系统后,若要离开系统,用户只要直接下达logout命令即可: [root@localhost root]# ...