服务热线: 17771845761

简述C#多核并行编程

作者: amvip
来源: uumtu
日期: 2018-11-19 17:57
阅读次数:

多核处理器的出现使得传统的串行编程模式无法利用多核、多处理器的优势,随着多核、多处理器平台的出现,多核编程也得到了更深层次的发展,而现在并行编程技术的发展并不能完全利用多核的优势,因而寻求新的并行编程技术是十分必要的。C#是.NET 平台中引入完全面向对象的编程语言,是C/C++的衍生语言,不但将C/C++的强大功能继承下来,并且去掉了它们的一些复杂特性,是一种能快速高效地实现基于.NET 平台软件开发的编程语言,且C#已经支持并发代码,这对于实现C#多核并行编程是十分必要且有利的。
  1 多核并行编程概述
  1.1 多核环境
  随着社会数字化、信息化的不断发展,对于计算机对数据的处理速度要求越来越快,在现代计算机技术的不断发展下,多核处理器已经成为计算机的处理器的主流,现代计算机大多都至少有一个双核的微处理器。
  多核处理器是将两个及其以上的具有完全功能的核心集成在同一个芯片上,并将整个芯片作为整体对外输出。多核处理器所集成的核心可以是单线程处理核心或多线程处理核心,集成后的多核处理器可同时执行的线程数或任务书是原本单处理器的数倍,这为处理器实现更高程度的并行提供了可能。并且,由于所有的核心都集成在片内,这就缩短了核心之间通信更高效,缩短核间的通信延迟,数据传输带宽也得到了提高。除此之外,由于多核处理器的集成性,功耗降低,提高了其片上资源的利用率。由于多核处理器结构简单,易于优化,扩展性强,这些特点使得多核的发展并逐渐取代单处理器成为主流。
  1.2. 并行编程
  传统的串行代码是顺序执行,且只用一个处理器,但随着现在多核的普及,串行程序无法充分利用多核的特点,这就促进了多核并行程序设计的出现。并行程序设计是指同时对多个任务、多条指令或多个数据项同时进行处理,是程序设计的一种形式,能够充分利用底层硬件所提供的并行执行能力从而提高程序的运行效率。
  并行程序设计的重点就是要找到程序中的并行性,尽可能降低由于并行化引起的开销。有时,并行化并不是优化算法的最佳选择,如果相比于串行执行的方式,并行化能够带来显著地性能提升,那么并行化才有意义。判断是否适合并行化并没有一劳永逸的方法——一切都取决于特定问题的功能需求和性能需求。在对现有程序进行并行优化的时候,必须理解现有的串行设计,或者理解提供了有限可扩展性的并行化算法,然后再对现有设计进行重构,从而使其获得性能提升,而且不会引入问题或产生不同的结果。在衡量程序并行化的效果时,可以用加速比来比较并行效果。其中,是加速比,是串行运算时间,也可表示为单处理器运行时间;是在有P 个核的处理器上的运行时间。
  1.3 NET Framework 4
  在传统的顺序式代码中,指令一条接着一条运行,这种方式并不能发挥多内核的优势,因为顺序指令只能运行在一个可用内核上。因此,在多核环境下,软件设计和程序编写能够准备好充分发挥多核系统的功能是一件十分重要的事情,但使用Visual C#2010 编写的顺序代码并不能发挥多核的优势,除非利用.NETFramework4 所提供的新功能将任务分解到多个内核上,Visual C#2010 和.NET Framework 4 使得将基于任务的设计转换为并行化代码变得非常简单。
  NET Framework 4.0 可实现创建并行代码新模型,这个新模型称为轻量级并发,这个模型减少了在不同逻辑内核上创建和执行代码所需要的总开销。这并不是说能够完全消除并行化带来的开销,但是这个模型本身是为现代多核微处理器而设计的。重量级并发模型是在多处理器的时代出现的,在那个时代计算机可能有很多物理微处理器,每个微处理器只有一个内核。轻量级的并发模型考虑了新的微架构,这个架构中有很多由一些物理内核支撑的逻辑内核。轻量级并发模型并不只是关注不同逻辑内核之间的作业调度,它还在框架级别添加了对多线程访问的支持,从而使得代码更容易理解。为了应对多核和众核的负载型,.NETFramework 引入了新的Task Parallel Library(任务并行库,TPL),TPL 是在多核时代应运而生的,TPL 提供了一个轻量级的框架,可以让开发人员可以应付各种不同的并行场合。
  2 C#并行编程
  TPL 引入了一个新的命名空间System.Threading.Task.通过这个命名空间可以引用.NET Framework 4 中并行编程所需要的类、结构和枚举。
  TPL 支持的数据场合主要包括以下三种。
  (1)数据并行(data parallelism)
  需要有大量数据需要处理,而且必须对每一份数据执行相同的操作。
  (2)任务并行(task parallelism)
  有很多可以并发运行的不同操作,通过任务并行发挥并行化的优势。
  (3)流水线(pipelining)
  是任务并行和数据并行的结合体。
  2.1 Parallel
  C#实现并行编程最简单、最基础的方法就是利用Parallel 类,在编写并行代码的时候通过使用Parallel 静态类(System.Threading.Tasks.Parallel)所提供的方法实现并行循环。
  2.1.1 Parallel. Invoke、Parallel.For、Parallel.ForEach
  在Parallel 下面有三个常用的方法Invoke,For 和ForEach。
  在需要使用的时候,引入命名空间System.Threading.Tasks,即可直接编辑Parallel.Invoke、Parallel.For、Parallel.ForEach 指令。Parallel.For——为固定数目的独立For 循环迭代提供了负载均衡的潜在并行执行。
  Parallel.ForEach——为固定数目的独立For Each 循环迭代提供了负载均衡的潜在的并行执行。这个方法支持自定义的分区器,可以更好地掌握数据分发。
  Parallel.Invoke——对给定的独立任务提供潜在的并行执行。
  2.1.2 Parallel 退出循环和异常处理
  (1)退出并行循环
  在串行循环中,想要退出循环,直接使用break 语句即可直接退出。但在并行循环中, 并行循环参数提供了一个ParallelLoopState,可用于终止Parallel.For 和Parallel.ForEach。ParallelLoopState 的loopState 实例提供了Break 和Stop 两种方法。
  Break——通知并行计算尽快退出循环,在完成当前迭代后尽快地停止执行。
  Stop——通知并行计算立即停止执行。
  (2)并行循环的异常处理
  在串行循环中,普通的Exception 就可捕获异常,但由于在并行计算过程中,多个迭代在同时进行,就会产生N 个异常并行出现,传统的异常管理方式已经不能满足,为并行计算而产生的新的System.AggregateException 即可捕获到并行计算中异常。AggregateException 包含了一个或多个在并行和并发代码执行过程中产生的异常。
  2.2 Task
  处理并行计算时,通常使用的方式就是多线程,在.NETFramework 4 之前使用最多的就是Thread,通过创建多个线程或者利用线程池的方法来实现并行计算。但在.NET Framework 4 之后,TPL 引入了新的基于任务的编程模型,这种编程模型同样可以充分发挥多核的优势,优化程序,不需要编写底层、复杂且重量级的线程代码,创建任务比创建线程具有更小的性能开销。但是任务和线程之间还是有区别的。
  (1)任务是架构在线程之上的,即任务运行的时候还是需要线程实现。
  (2)任务与线程之间并不是一对一的关系,一个线程可以运行多个任务,一个任务也可由多个线程完成。
  (3)创建任务相较于创建线程而言开销更小。
  2.2.1 Task 的生命周期
  Task 的初始状态:
  Created:利用构造函数创建Task 实例时的初始状态,利用
  Task.Factory.StartNew 创建时直接跳过。
  WaitingToRun:利用Task.Factory.StartNew 进行创建时的初始状态。
  RanToCompletion:任务执行完毕。
  创建Task 的方法有两种:
  (1)利用构造函数
  vartask1=new Task()(=>{ });
  (2)利用Task.Factory.StartNew 进行创建Var task2=Task.Factory.StartNew()(=>{ });
  2.2.2 Task 的任务控制
  Task 的特点就在于其任务控制部分,编程人员可以通过调整Task 的执行顺序,从而实现Task 的有序工作,Task 提供了以下几种方法。
  (1)Task.Wait()——当前线程一直等待任务执行完成后执行。
  (2)Task.WaitAll()——当前线程会等待Task 实例以Task数组的形式作为参数被接受,Task 之间通过逗号隔开,这个方法是同步执行的。
  (3)Task.ContinueWith()——第一个Task 完成后自动启动下一个Task,实现Task 的延续。
  (4)Task 的取消
  Task 是并行计算的,在.NET Framework 4.0 中提供了一个取消标记(CancellationTokenSource.Token),在创建task 的时候传入此参数,就可以将主线程和任务相关联,然后在任务中调用ThrowIfCancellationRequested 方法来等待主线程使用Cancel 来通知,一旦cancel 被调用,task 将会抛出OperationCanceledException来中断此任务的执行,Task 实例会转入TaskStatus.Canceled 状态,并且IsCanceled 属性才回被设置为true。
  2.2.3 Task 的异常处理
  当很多任务并行运行的时候,可能会并行发生很多异常。Task 实例能够处理一组一组的异常, 这些异常利用System.AggregateException 类处理。初次之外,通过Task 的属性也可判断Task 的状态,例如:IsCompleted,IsFaulted,IsCancelled等。
  3 总结
  随着多核时代的到来,多核并行编程已然成为并行编程的主流模式,.NET Framework 4.0 增加的TPL,很好地满足了多核处理器的应用要求。Parallel 类和Task 类的出现使得在编写并行计算的程序时,不需要考虑底层的运行机制,极大地简化了程序的复杂性,并且相较于之前通过创建多线程实现并行编程的方法而言,程序性能开销更小,更灵活。所以,在用C#实现多核并行编程时,可以更多地通过TPL 的方式实现。


?17771845761
地址:武汉市东湖新技术开发区光谷大道3号激光工程设计总部二期研发楼
Copyright © 武汉天地智作文化传播有限公司 All Right Reserved.
X
3

SKYPE 设置

4

阿里旺旺设置

5

电话号码管理

6

二维码管理

展开

免责声明: 本站资料及图片来源互联网文章,本网不承担任何由内容信息所引起的争议和法律责任。所有作品版权归原创作者所有,与本站立场无关,如用户分享不慎侵犯了您的权益,请联系我们告知,我们将做删除处理!