您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 管理学资料 > .NET 4 并行(多核)编程系列
.NET4并行(多核)编程系列之一入门介绍本系列文章将会对.NET4中的并行编程技术(也称之为多核编程技术)以及应用作全面的介绍。本篇文章的议题如下:1.并行编程和多线程编程的区别。2.并行编程技术的利弊3.何时采用并行编程1.并行编程和多线程编程的区别。1.1并行编程。现在随着多核计算机的普及,并行编程技术,也就是多核编程技术也逐渐称为开发的主流。为此,在.NET4中就引入了“并行编程”。在.NET4中一些列的Library和类为并行编程提供了支持,如:TaskParallelLibrary,ParallelLINQ等。其实在.NET1.0中就有了并行编程技术的一些实现---多线线程技术。多线程最大的问题就是难于使用和管理。在使用多线程的使用,因为它的复杂性,往往使用我们把注意力分散了多线程上。而致使我们的最初目的被掩盖了。1.2比较区别在.NET4中提出的并处编程的底层机制其实还是基于多线程的。但是他们之前最大的区别就是.NET4中的并行编程更加方便。在传统的编程模型中,程序员负责创建线程,为线程分配任务,管理线程。一个形象的比喻:你拥有一批士兵,然后你对他们下达命令,之后,你就必须时刻监视你的那些士兵,确保他们按照你的意图办事。(很累吧!)在.NET4中的并行编程是依赖TaskParallelLibrary(后面简称为TPL)实现的。在TPL中,最基本的执行单元是task(中文可以理解为任务),一个task就代表了你要执行的一个操作。你可以为你所要执行的每一个操作定义一个task,TPL就负责创建线程来执行你所定义的task,并且管理线程。TPL是面向task的,自动的;而传统的多线程是以人工为导向的。Task机制使得我们把注意力关注在我们要解决的问题上面。如果之前的多线程技术使得我们放弃了一些并行编程的使用,那么.NET4中的新的并行编程技术可以让我们重新建立信心。虽然有了新的并行技术,但是传统的多线程的技术还是很有用的。当我们使用TPL中的并行技术的时候来执行多个task的时候,我们不用在关心底层创建线程,管理线程等。2.并行编程技术的利弊使用并行技术最大的好处就是提高了系统的性能。并行处理过程一般是这样的:一个要执行的任务被拆分为很多很小的部分,然后这些很小的部分就分别在不同处理器(可以是多核的一台电脑,也可以使很多的电脑)上执行。因为这些很多很小的部分同时在执行,所以称之为并行。使用并处编程的时候需要考虑下面的问题:1.开销问题。并行执行不是免费的,也是要开销的。在并行运行开始和管理都是需要开销的,就类比在线程的创建和管理一样。在程序中,你要执行的任务越多,那么使用并行的效果就越好。2.数据的协调如果在并行执行的那些小部分需要共享公共的数据,那么我们就要协调。一般来说,需要协调的数据越多,并行执行的性能损耗就越大。如果执行各个小部分之间都是独立的,那么我们就不用协调了。但是很多的时候,我们都是需要协调的。而且协调的技术也不是很难,在之后的文章中会一一讲述。3.性能提高多少增加一台计算机的CPU可能会提高程序的运行速度,但是不是绝对的。我们知道,一个应用程序在单核的计算机上运行的时间不一定(往往也不是)双核计算机的1/2.所以,采用并行编程不一定就一定会成倍的提高程序的性能。因为性能与很多的因数有关的,硬件就是很大的因数。3.何时采用并行编程建议:如果一个问题能够用并行编程解决,那么就用,否则就不用。听起来好像是废话,但是确实是一个很不错的建议。因为并行编程也不是万能的,也只能解决一类的问题,所以在用之前要分析问题了。如果一个问题确实能够用并行的方案来解决,但是有很多的因数影响,如之前我们提到的一些问题。权衡使用之后的开销和好处在决定是否使用。后续文章会给出很多的例子。.NET4并行(多核)编程系列之二从Task开始前言:我们一步步的从简单的开始讲述,还是沿用我一直的方式:慢慢演化,步步为营。本篇文章的议题如下:1.Task基础介绍2.Task的创建3.获取Task的执行结果4.补充细节1.Task基础介绍首先我们还是来看看一段简单的代码:这里展示的只是一段简单的代码,不能显示出并行编程的特点。但是我们还是从最基本的开始看,慢慢进入深一点的话题。如果你曾经用过.NET中的多线程编程,比较一下,就会发现:这段代码虽然在底层还是使用了多线程,但是写法上却简化了很多,一行代码就实现了一个并行编程。下面我们就从Task类开始谈。Task类是TaskProgrammingLibrary(TPL)中最核心的一个类,下面我将会像大家展示如何使用一些方法来创建不同类型的Task,取消Task,等待Task执行完成,获取Task执行后的结果和对异常进行处理。在开始讨论之前,我们首先快速的看看之前的代码:这个命名空间将会是我们之后在讲述并行编程经常使用的一个。这个空间包含了很多与并行编程有关的类。还有一个要你使用的命名空间是:System.Threading,大家对这个应该比较熟悉了,之前的多线程编程常常使用到,这个空间下包含了一些在并行编程中用来协调数据的一些类。上面代码中,最主要的代码如下:Task.Factory.StartNew(()={Console.WriteLine(HelloWorld);});我们用静态方法: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实例开始运行的时候,它就被传给了内部的一个taskscheduler,这个scheduler负责把我们创建的task交给底下的线程去执行。下面就看看代码:代码usingSystem;usingSystem.Threading.Tasks;namespaceListing_02{classListing_02{staticvoidMain(string[]args){//useanActiondelegateandanamedmethodTasktask1=newTask(newAction(printMessage));//useaanonymousdelegateTasktask2=newTask(delegate{printMessage();});//usealambdaexpressionandanamedmethodTasktask3=newTask(()=printMessage());//usealambdaexpressionandananonymousmethodTasktask4=newTask(()={printMessage();});task1.Start();task2.Start();task3.Start();task4.Start();//waitforinputbeforeexitingConsole.WriteLine(Mainmethodcomplete.Pressentertofinish.);Console.ReadLine();}staticvoidprintMessage(){Console.WriteLine(HelloWorld);}}}不知道大家注意到了没有,上面代码创建Task的方法和我们之前的第一段代码的创建Task的方法不同。在之前我们采用的是Task.Factory.StartNew()方法来创建的,这个方法创建Task并且开始运行Task,其实两端代码的结果是一样的,这里给出一点建议:如果这是想简单的创建一个Task,那么使用Factory.NewStart()来创建,很简便,如果像对所创建的Task附加更多的定制和设置特定的属性,那么还是得一步一步的按照我们说的那些步骤来。(详细的我们后续会介绍的)2.1为创建的Task传入参数我们之前提过,在创建Task的时候,我们在构造函数中传入了一个System.Action的委托,如果我们想要把一些参数传入到Task中,那么我们可以传入System.Actionobject的委托,其中的那个object就是我们传入的参数。还是给大家举个例子:代码usingSystem;usingSystem.Threading.Tasks;namespaceListing_04{classListing_04{staticvoidMain(string[]args){string[]messages={Firsttask,Secondtask,Thirdtask,Fourthtask};foreach(stringmsginmessages){TaskmyTask=newTask(obj=printMessage((string)obj),msg);myTask.Start();}//waitforinputbeforeexitingConsole.WriteLine(Mainmethodcomplete.Pressentertofinish.);Console.ReadLine();}staticvoidprintMessage(stringmessage){Console.WriteLine(Message:{0},message);}}}注意:我们在传入参数后,必须把参数转换为它们原来的类型,然后再去调用相应的方法。例子中,因为System.Action对应的方法是printMessage()方法,而这个方法的要求的参数类型是string,所以要转换为string。想向Task传入参素,只能用System.Actionobject3.获取Task的执行结果如果要获取Task的结果,那么在创建Task的时候,就要采用TaskT来实例化一个Task,其中的那个T就是task执行完成之后返回结果的类型。之后采用Task实例的Result属性就可以获取结果。代码显示如下:代码staticvoidMain(string[]args){//createthetaskTaskinttask1=newTaskint(()={intsum=0;for(inti=0;i100;i++){sum+=i;}returnsum;});task1.Start();//writeouttheresultConsole.WriteLine(Result1:{0},task1.Result);Console.ReadLine();}只有在task执行完成之后,才能获取到Result的值。下面的代码展示了如何通过Task.Factory.StartNewT()创建一个Task,并且获取结果:代码staticvoidMain(string[]args){//createthetaskTaskinttask1=Task.Factory.StartNewint(()={intsum=0;for(inti=0;i100;i++){sum+=i;}returnsum;});//writeouttheresultConsole.WriteLine(Result1:{0},task1.Result);Console.ReadLine();}4.补充细节在创建Task的时候,Task有很多的构造函数
本文标题:.NET 4 并行(多核)编程系列
链接地址:https://www.777doc.com/doc-3348591 .html