.NET4并行(多核)编程系列
《.NET4并行(多核)编程系列》由会员分享,可在线阅读,更多相关《.NET4并行(多核)编程系列(23页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、 .NET 4 并行(多核)编程系列之一入门介绍 本系列文章将会对.NET 4 中的并行编程技术(也称之为多核编程技术)以及应用作全面的介绍。本篇文章的议题如下:1.并行编程和多线程编程的区别。2.并行编程技术的利弊 3.何时采用并行编程 1.并行编程和多线程编程的区别。1.1 并行编程。现在随着多核计算机的普及,并行编程技术,也就是多核编程技术也逐渐称为开发的主流。为此,在.NET 4 中就引入了“并行编程”。在.NET 4 中一些列的 Library 和类为并行编程提供了支持,如:Task Parallel Library,Parallel LINQ 等。其实在.NET 1.0 中就有了并
2、行编程技术的一些实现-多线线程技术。多线程最大的问题就是难于使用和管理。在使用多线程的使用,因为它的复杂性,往往使用我们把注意力分散了多线程上。而致使我们的最初目的被掩盖了。1.2 比较区别 在.NET 4 中提出的并处编程的底层机制其实还是基于多线程的。但是他们之前最大的区别就是.NET 4 中的并行编程更加方便。在传统的编程模型中,程序员负责创建线程,为线程分配任务,管理线程。一个形象的比喻:你拥有一批士兵,然后你对他们下达命令,之后,你就必须时刻监视你的那些士兵,确保他们按照你的意图办事。(很累吧!)在.NET 4 中的并行编程是依赖 Task Parallel Library(后面简称
3、为 TPL)实现的。在 TPL中,最基本的执行单元是 task(中文可以理解为任务),一个 task 就代表了你要执行的一个操作。你可以为你所要执行的每一个操作定义一个 task,TPL 就负责创建线程来执行你所定义的task,并且管理线程。TPL 是面向 task 的,自动的;而传统的多线程是以人工为导向的。Task 机制使得我们把注意力关注在我们要解决的问题上面。如果之前的多线程技术使得我们放弃了一些并行编程的使用,那么.NET 4 中的新的并行编程技术可以让我们重新建立信心。虽然有了新的并行技术,但是传统的多线程的技术还是很有用的。当我们使用 TPL 中的并行技术的时候来执行多个 tas
4、k 的时候,我们不用在关心底层创建线程,管理线程等。2.并行编程技术的利弊 使用并行技术最大的好处就是提高了系统的性能。并行处理过程一般是这样的:一个要执行的任务被拆分为很多很小的部分,然后这些很小的部分就分别在不同处理器(可以是多核的一 .台电脑,也可以使很多的电脑)上执行。因为这些很多很小的部分同时在执行,所以称之为并行。使用并处编程的时候需要考虑下面的问题:1.开销问题。并行执行不是免费的,也是要开销的。在并行运行开始和管理都是需要开销的,就类比在线程的创建和管理一样。在程序中,你要执行的任务越多,那么使用并行的效果就越好。2.数据的协调 如果在并行执行的那些小部分需要共享公共的数据,那
5、么我们就要协调。一般来说,需要协调的数据越多,并行执行的性能损耗就越大。如果执行各个小部分之间都是独立的,那么我们就不用协调了。但是很多的时候,我们都是需要协调的。而且协调的技术也不是很难,在之后的文章中会一一讲述。3.性能提高多少 增加一台计算机的 CPU 可能会提高程序的运行速度,但是不是绝对的。我们知道,一个应用程序在单核的计算机上运行的时间不一定(往往也不是)双核计算机的 1/2.所以,采用并行编程不一定就一定会成倍的提高程序的性能。因为性能与很多的因数有关的,硬件就是很大的因数。3.何时采用并行编程 建议:如果一个问题能够用并行编程解决,那么就用,否则就不用。听起来好像是废话,但是确
6、实是一个很不错的建议。因为并行编程也不是万能的,也只能 解决一类的问题,所以在用之前要分析问题了。如果一个问题确实能够用并行的方案来解决,但是有很多的因数影响,如之前我们提到的一些问题。权衡使用之后的开销和好处在决定是否使用。后续文章会给出很多的例子。.NET 4 并行(多核)编程系列之二 从 Task 开始 前言:我们一步步的从简单的开始讲述,还是沿用我一直的方式:慢慢演化,步步为营。本篇文章的议题如下:1.Task 基础介绍 2.Task 的创建 3.获取 Task 的执行结果 4.补充细节 1.Task 基础介绍 .首先我们还是来看看一段简单的代码:这里展示的只是一段简单的代码,不能显示
7、出并行编程的特点。但是我们还是从最基本的开始看,慢慢进入深一点的话题。如果你曾经用过.NET 中的多线程编程,比较一下,就会发现:这段代码虽然在底层还是使用了多线程,但是写法上却简化了很多,一行代码就实现了一个并行编程。下面我们就从 Task 类开始谈。Task 类是 Task Programming Library(TPL)中最核心的一个类,下面我将会像大家展示如何使用一些方法来创建不同类型的 Task,取消 Task,等待 Task 执行完成,获取 Task 执行后的结果和对异常进行处理。在开始讨论之前,我们首先快速的看看之前的代码:这个命名空间将会是我们之后在讲述并行编程经常使用的一个。
8、这个空间包含了很多与并行编程有关的类。还有一个要你使用的命名空间是:System.Threading,大家对这个应该比较熟悉了,之前的多线程编程常常使用到,这个空间下包含了一些在并行编程中用来协调数据的一些类。上面代码中,最主要的代码如下:Task.Factory.StartNew()=Console.WriteLine(Hello World););我们用静态方法:Task.Factory.StartNew()来创建了一个最简单的 Task-在屏幕上打印一句话。这段代码确实简单,而且都没有任何输入和需要返回的结果。下面我们就正式进入议题:2.Task 的创建 如果只是创建一个简单的 Task
9、,我们只要为该 Task 提供一个执行体就行了,执行体可以是一个委托 delegate 或者 action。我们之前展示的那段代码就是采用了 lambda 表达式来作为Task 的执行体。.2.1 创建一个简单的 Task 为了执行一个简单的 Task,一般进行以下步骤:首先,要创建一个 Task 类的实例,然后,传入一个 System.Action 委托,这个委托中的方法就是这个 Task 运行时你要执行的方法,而且这个委托必须作为 Task 构造函数的一个参数传入。我们在传入委托作为参数的时候有多种方式:传入匿名委托,Lambda 表达式或者一个显示什么方法的委托。最后,调用 Task 实
10、例的 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(printMe
11、ssage);/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.Sta
12、rt();/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,其实两端代码的结果是
13、一样的,这里给出一点建议:如果这是想简单的创建一个 Task,那么使用 Factory.NewStart()来创建,很简便,如果像对所创建的 Task附加更多的定制和设置特定的属性,那么还是得一步一步的按照我们说的那些步骤来。(详细的我们后续会介绍的)2.1 为创建的 Task 传入参数 我们之前提过,在创建 Task 的时候,我们在构造函数中传入了一个 System.Action 的委托,如果我们想要把一些参数传入到 Task 中,那么我 们可以传入 System.Action的委托,其中的那个 object 就是我们传入的参数。还是给大家举个例子:代码 using System;using
14、 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.WriteL
15、ine(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 3.获取
16、 Task 的执行结果 如果要获取 Task 的结果,那么在创建 Task 的时候,就要采用 Task来实例化一个Task,其中的那个 T 就是 task 执行完成之后返回结果的类型。之后采用 Task 实例的 Result属性就可以获取结果。代码显示如下:代码 static void Main(string args)/create the task Task task1=new Task()=int sum=0;for(int i=0;i 100;i+).sum+=i;return sum;);task1.Start();/write out the result Console.Writ
17、eLine(Result 1:0,task1.Result);Console.ReadLine();只有在 task 执行完成之后,才能获取到 Result 的值。下面的代码展示了如何通过 Task.Factory.StartNew()创建一个 Task,并且获取结果:代码 static void Main(string args)/create the task Task task1=Task.Factory.StartNew()=int sum=0;for(int i=0;i 100;i+)sum+=i;return sum;);/write out the result Console.
18、WriteLine(Result 1:0,task1.Result);Console.ReadLine();4.补充细节 在创建 Task 的时候,Task 有很多的构造函数的重载,一个主要的重载就是传入TaskCreateOptions 的枚举:TaskCreateOptions.None:用默认的方式创建一个 Task TaskCreateOptions.PreferFairness:请求 scheduler 尽量公平的执行 Task(后续文章会 .将是,Task 和线程一样,有优先级的)TaskCreateOptions.LongRunning:声明 Task 将会长时间的运行。Task
19、CreateOptions.AttachToParent:因为 Task 是可以嵌套的,所以这个枚举就是把一个子 task 附加到一个父 task 中。最后要提到的一点就是,我们可以在 Task 的执行体中用 Task.CurrentId 来返回 Task 的唯一表示 ID(int)。如果在 Task 执行体外使用这个属性就会得到 null。.NET 4 并行(多核)编程系列之三 从 Task 的取消 前言:因为 Task 是.NET 4 并行编程最为核心的一个类,也我们在是在并行编程常常打交道的类,所以,对 Task 对全面的了解很有必要。上篇文章主要讲述了如何创建一个 task,本篇文章主
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- NET4 并行 多核 编程 系列
限制150内