将并发运行时与其他并发模型进行比较
本文档描述并发运行时和其他技术在功能和编程模型方面的差异。 通过了解并发运行时的好处与其他编程模型的好处的比较情况,您可以选择最符合您的应用程序要求的技术。
如果您当前使用的是另一种编程模型(如 Windows 线程池或 OpenMP),那么在某些情况下则适合迁移到并发运行时。 例如,从 OpenMP 迁移至并发运行时主题描述了何时适合从 OpenMP 迁移到并发运行时。 但是,如果您对应用程序性能和当前的调试支持感到满意,则可能不需要进行迁移。
您可以使用并发运行时的功能和生产力优势来补充使用另一种并发模型的现有应用程序。 当多个任务计划程序争用同一计算资源时,并发运行时无法保证负载平衡。 但当工作负载不重叠时,这种影响非常小。
各节内容
比较抢先式计划与协作式计划
比较并发运行时与 Windows API
比较并发运行时与 OpenMP
比较抢先式计划与协作式计划
抢先式模型和协作式计划模型是使多个任务可以共享计算资源(如处理器或硬件线程)的两种常见方法。
抢先式和协作式计划
“抢先式计划”是基于优先级别的循环机制,它为每个任务授予一段给定时间的计算资源独占访问权,然后切换到另一个任务。 抢先式计划在多任务操作系统(如 Windows)中很常见。协作式计划是一种机制,它为每个任务授予计算资源的独占访问权,直到任务完成或直到任务让出它对该资源的访问权。 并发运行时一同使用操作系统的协作式计划和抢先式计划程序,以达到处理资源的最大使用率。
抢先式和协作式计划程序之间的差异
抢先式计划程序寻求为多个线程授予相等的计算资源访问权限,以确保每个线程都可以取得进展。 在具有很多计算资源的计算机上,确保公平访问已不成问题;但是,确保资源的高效利用越来越成为问题。
抢先式内核模式计划程序要求应用程序代码依靠操作系统制定计划决策。 相反,用户模式协作式计划程序使应用程序代码可以制定其自己的计划决策。 由于协作式计划允许许多计划决策由应用程序制定,因此它减少了与内核模式同步关联的大部分系统开销。 协作式计划程序通常在没有其他工作要计划时,交由操作系统内核来制定计划决策。 协作式计划程序还在有一个传递给内核的阻止操作,但该操作不传递给用户模式计划程序时,交由操作系统计划程序制定计划决策。
协作式计划和效率
对于抢先式计划程序而言,所有具有相同优先级别的工作都是相等的。 抢先式计划程序通常按线程的创建顺序计划线程。 此外,抢先式计划程序根据线程优先级别,以循环方式为每个线程提供一个时间片。 虽然此机制保证了公平(每个线程都取得进展),但它造成效率的一些下降。 例如,许多计算密集型算法并不要求公平。 而重要的是相关任务要以最少的总时间完成。 协作式计划使应用程序可以更高效地计划工作。 例如,考虑一个具有多个线程的应用程序。 计划不共享资源即可同时运行的线程可以减少同步开销,从而提高了效率。 计划任务的另一个高效方式是在同一处理器上运行任务管道(其中每个任务作为前一个任务的输出),以便每个管道阶段的输入加载到内存缓存。
一同使用抢先式和协作式计划
协作式计划不能解决所有计划问题。 例如,不向其他任务公平让出资源的任务可能消耗所有可用计算资源,阻止其他任务取得进展。 并发运行时使用协作式计划的高效优点来补充抢先式计划的公平保证。 默认情况下,并发运行时提供一个协作式计划程序,该计划程序使用工作窃取算法在计算资源之间高效地分配工作。 但是,并发运行时计划程序也会依赖操作系统的抢先式计划程序在应用程序之间公平地分配资源。 您还可以在应用程序中创建自定义计划程序和计划程序策略,以对线程执行进行精细控制。
Top
比较并发运行时与 Windows API
Microsoft Windows 应用程序编程接口(通常称为 Windows API,以前称为 Win32)提供了在应用程序中启用并发的编程模型。 并发运行时基于 Windows API 生成,以提供无法从基础操作系统获得的附加编程模型。
并发运行时基于 Windows API 线程模型生成以执行并行工作。 它还使用 Windows API 内存管理和线程本地存储机制。 在 Windows 7 和 Windows Server 2008 R2 上,它将 Windows API 支持用于用户可计划线程和具有 64 个以上硬件线程的计算机。 并发运行时扩展 Windows API 模型,方法是通过提供协作式任务计划程序和工作窃取算法以最大限度地提高计算资源的使用率,以及通过启用多个同时发生的计划程序实例。
有关 Windows API 的更多信息,请参见 Windows API 概述。
编程语言
Windows API 使用 C 编程语言公开编程模型。 并发运行时提供了一个利用 C++ 语言中的最新功能的 C++ 编程接口。 例如,lambda 函数提供一种简洁的、类型安全的机制,用于定义并行工作函数。 有关并发运行时使用的最新 C++ 功能的更多信息,请参见并发运行时的概述。
线程和线程池
Windows API 中的中心并发机制是线程。 通常,使用 CreateThread 函数创建线程。 虽然线程的创建和使用相当容易,但是操作系统分配了大量时间和其他资源来管理它们。 此外,虽然保证每个线程都接收与同一优先级别的任何其他线程相同的执行时间,但关联开销要求您创建足够大的任务。 对于较小的或更细化的任务,与并发相关联的开销可能超过了并行运行这些任务的好处。
线程池是一种降低线程管理成本的方法。 自定义线程池和 Windows API 提供的线程池实现都使小的工作项可以高效并行运行。 Windows 线程池维护先入先出 (FIFO) 队列中的工作项。 每个工作项都按其添加到池中的顺序启动。
并发运行时实现工作窃取算法来扩展 FIFO 计划机制。 该算法将尚未开始的任务移动到用完工作项的线程。 虽然工作窃取算法可以平衡工作负荷,但它还可能导致工作项重新排序。 此重新排序过程会导致工作项按与提交顺序不同的顺序启动。 这对于递归算法很有用,在递归算法中,数据有更好的机会在较新任务之间共享,而不是在较旧的任务之间共享。 让新项首先运行意味着缓存未命中情况较少且页错误可能较少。
从操作系统的角度而言,工作窃取是不公平的。 但是,当应用程序实现要并行运行的算法或任务时,子任务之间的公平始终无关紧要。 重要的是总体任务的完成速度。 对于其他算法,FIFO 是恰当的计划策略。
在各种操作系统上的行为
在 Windows XP 和 Windows Vista 上,使用并发运行时的应用程序的行为相似,只不过在 Windows Vista 上堆性能得到了改善。
在 Windows 7 和 Windows Server 2008 R2 上,操作系统进一步支持并发性和可伸缩性。 例如,这些操作系统支持具有 64 个以上硬件线程的计算机。 使用 Windows API 的现有应用程序必须经过修改才能利用这些新功能。 但是,使用并发运行时的应用程序自动使用这些功能,不需要修改。
https://msdn.microsoft.com/zh-cn/library/dd627187(v=vs.110)
Top
比较并发运行时与 OpenMP
并发运行时启用各种编程模型。 这些模型可能会重叠或补充其他库的模型。 本节将并发运行时与 OpenMP 进行比较。
OpenMP 编程模型是由开放标准定义的,具有与 Fortran 和 C/C++ 编程语言的定义完善的绑定。 OpenMP 2.0 和 2.5 版非常适合于迭代的并行算法,也就是说,它们在数据数组上执行并行迭代。 当并行度是预先确定的并与系统上的可用资源相匹配时,OpenMP 效率最高。 OpenMP 模型特别适合于高性能计算,在高性能计算中,跨一台计算机的处理资源分布了大量计算问题。 在此方案中,硬件环境是已知的,开发人员可以合理地期望在执行该算法时拥有对计算资源的独占访问权。
但是,其他约束较少的计算环境可能不是 OpenMP 的绝佳匹配。 例如,使用 OpenMP 更难以实现递归问题(如数据的 quicksort 算法或搜索树)。 通过提供并行模式库 (PPL) 和异步代理库,并发运行时对 OpenMP 的功能进行了补充。 与 OpenMP 不同,并发运行时提供动态计划程序,该计划程序在工作负荷更改时可以适应可用资源和调整并行度。
可以扩展并发运行时中的许多功能。 您还可以组合现有功能来构成新功能。 由于 OpenMP 依赖于编译器指令,它不能很容易地进行扩展。
有关并发运行时和 OpenMP 的比较情况以及如何迁移现有 OpenMP 代码以使用并发运行时的更多信息,请参见从 OpenMP 迁移至并发运行时。
Top