基于任务模型的并发编程(二)
并发编程和多核编程
传统的顺序代码一个指令一个指令的执行,并不能充分的利用多核的优势,因为这些串行执行的指令仅仅能够运行在这些内核中的某一个。使用visual C# 2010编写的顺序代码,如果没有使用.NET 4.0提供的新特性将任务分派到多个核心上,那也是不能充分的利用多核心的优势的。对于已存的顺序代码并不存在一种自动的并发。
并发编程是一种代码充分的利用底层硬件提供的并行执行能力的编程模式。并发编程模式同时运行很多的指令。就像前面所解释的,现在又很多不同种类的并行执行架构,并且对他们就这一话题的细节进行深入分析需要一整本书来展现。
多核编程是一种代码充分的利用多个正在执行的内核来并行的运行很多的指令的编程模型。多核心和多处理器的单台电脑提供了多于一个处理核心。因此,这样的目的就是通过将工作分布到所有可用的核心上完成,从而达到在更少的事件内做更多的事情。
现在的微处理器可以在多样的数据上执行相同的指令,这就是Michael J. Flynn 在1966年他所推荐的Flynn’s taxonomy所总结的单指令多数据。以这种方式,你可以充分的利用这些向量处理机来减少执行特定算法的执行事件。
这本书同时覆盖了共享内存多核编程和向量处理能力使用的两种并发编程模型的很多细节。这一切的首要目的就是减少算法的执行时间。新的处理能力是你能够为已存的代码添加新的特性。
理解物理线程和软件线程
一个多核的微处理器拥有多于一个的物理处理核心,这些彼此独立的处理单元使得同时并行执行多条执行成为可能。为了充分的利用这些物理核心,我们有必要运行多个进程或者在单个进程内运行多个线程。
然而,每一个物理核心都能够提供多于一个的物理线程,这个就是众所周知的逻辑核心或者逻辑处理器。使用英特尔的Hyper-Threading技术(HT或者HTT)的微处理器为每个物理核心提供了多个架构级别的状态。例如,很多使用HT技术带有四个物理核心的微处理器为每个物理核心提供了两个架构级别的状态,也就是提供了八个物理线程。这就是众所周知的SMT(simultaneous multiithreading)技术,它在微处理器指令级别使用额外的架构级别的状态来优化和增强并行执行能力。SMT技术并没有限制每个物理核心仅仅可以提供两个物理线程;例如,每个物理核心你可以拥有四个物理线程。这并不意味着每个物理线程就代表一个物理核心。在某些特定的场景下,SMT能够为多线程代码提供性能优化。后续的章节将会提供有关这些性能优化方面的例子。
每个运行在windows上的程序就是一个进程。每个进程会创建和运行一个或者多个线程。为了区别先前的提到的物理线程,我们将其称为软件线程。一个进程至少得有一个主线程。一个操作系统调度器为他所调度需要运行的进程和线程公平的分配可用处理资源。Windows调度器为每一个软件线程分配处理时间。当windows调度器运行在多核处理器上时,它必须冲一个物理线程分配处理时间到每一个需要运行指令的软件线程上。你可以讲每个物理线程想象为泳道,每个软件线程想象为游泳者。
每一个软件线程都与它所属的进程共享私有的内存空间,然而它却有自己的堆栈、寄存器和私有局部存储器。
Windows将每个物理线程视为一个可以调度的逻辑处理器。每个逻辑处理器都能都执行同一个软件线程的代码。一个执行多个软件线程代码的进程可以充分的利用物理线程和物理核心来并行执行指令。图1-4中展示了运行在物理线程和物理核心上的软件线程的情况。Windows调度器为了均衡每个物理线程的工作负载,可以决定是否重新指派一个软件线程到另一个物理线程。因为通常有很多其他的软件线程等待处理时间,负载均衡通过组织这些线程的可用资源使得运行这些软件线程称为可能。图1-5中windows任务管理器展示了8个物理线程(逻辑核心和它们的负载)。
图 1-4
图 1-5
负载均衡是这样一种分布实践,它将软件进程上的工作在硬件进程上进行重新分配。然而,成功的实现一个完美的负载均衡需要依赖包括应用程序、工作负载、软件线程的数目、可用的物理线程和负载均衡策略在内的并行实现。
Windows任务管理器和windows资源监视器展示了cpu的物理线程的使用率图表。例如,如果你有一个拥有四个物理核心的微处理器和八个物理线程,这些工具将会展示八个独立的图表。
Windows通过将大量的处理时间指派给每个可用的物理线程的方式运行着成百的软件线程。你可以在windows资源监视器的概述标签页中查看一个指定进程的所有软件线程的数目。CPU仪表盘展示了每个进程的名字,在Threads列中展示了相关联的软件线程的数目,在图1-6中我们可以看到vlc.exe进程拥有32个软件线程。
图 1-6
Core Parking是windows内核能源管理器和内核调度技术,它是为改善多核系统的能效问题而设计的。它不断的跟踪每个物理线程相对其他所有物理线程的工作负载来决定是否让它们中的某些进入睡眠模式。
Core Parking基于工作负载动态的调整正在使用的物理线程的数量。当某个物理线程的工作负载小于某个特定的临界值的时候,Core Parking算法将会尝试通过停止系统中某些物理线程来减少正在使用的物理线程的数目。为了改善这种算法的有效性,当调度软件线程的时候,内核调度器可以给予没有停止的物理线程优先权。它将会尝试让停止的软件线程停顿,这样就可以使他们转换成为一种低耗能的停顿状态。
Core Parking尝试只能调度那些运行带多个软件线程的工作负载,这些线程运行在使用HT技术的微处理器的某个物理核心上。这种调度决定减少了能源消耗。
Windows server 2008 R2支持完整的Core Parking技术。然而,windows 7也使用Core Parking算法和基础设施来平衡运行在带有HT功能的微处理器上的物理线程的性能。图1-7中的资源监视器展示了八个物理线程的活动状态,其中四个是parked状态。
尽管某些物理线程处于parked状态,但是使用.NET 4的方法获取的物理线程的数目还是总的数目。Core Parking技术并不限制可用来运行进程内的软件线程的可用的物理线程的数目。
在特定的工作负载下,一个有八个物理线程的系统在工作负载比较轻时使自己只有两个物理线程,然后在需要的时候再增加运行保留的物理线程。在某些情况下,Core Parking会引入一个额外的潜在因素来调度很多想要并行执行代码的软件线程。所以,在测量并行执行性能的时候,考虑这些影响结果的潜在因素是很重要的。
图 1-7