第 22 章 并行编程 并行编程
本作品已使用人工智能进行翻译。欢迎您提供反馈和意见:translation-feedback@oreilly.com
本章将介绍旨在利用多核处理器的多线程应用程序接口和结构:
并行 LINQ 或PLINQ
Parallel类任务并行结构
同时收集
这些构造统称为并行框架(PFX)。Parallel 类与任务并行构造一起被称为任务并行库(TPL)。
在阅读本章之前,你需要熟悉第 14 章中的基础知识,尤其是锁定、线程安全和Task 类。
备注
.NET还提供了许多专门的应用程序接口,以帮助进行并行和异步编程:
System.Threading.Channels.Channel是一种高性能异步生产者/消费者队列,在 .NET Core 3 中引入。Microsoft Dataflow(位于
System.Threading.Tasks.Dataflow命名空间)是一个复杂的 API,用于创建缓冲块网络,并行执行操作或数据转换,与演员/代理编程有异曲同工之妙。Reactive Extensions实现了
IObservable上的 LINQ(IAsyncEnumerable的另一种抽象),擅长结合异步流。反应式扩展包含在System.ReactiveNuGet 软件包中。
为什么选择 PFX?
在过去的 15 年中,CPU 制造商已经从单核处理器转向多核处理器。这对我们程序员来说是个问题,因为单线程代码不会因为多了这些内核而自动运行得更快。
对于大多数服务器应用程序来说,利用多核很容易,每个线程都可以独立处理单独的客户端请求,但在桌面上就比较困难了,因为这通常需要你将计算密集型代码做如下处理:
将其分割成小块。
通过多线程并行执行这些分块。
以线程安全和高效的方式整理可用结果。
虽然您可以使用经典的多线程结构来完成所有这些工作,但这很不方便,尤其是分区和整理步骤。另一个问题是,当多个线程同时处理相同数据时,为线程安全加锁的常规策略会导致大量争用。
PFX 库就是专门为这些情况而设计的。
备注
利用多核或多处理器进行编程称为并行编程。这是更广泛的多线程概念的一个子集。
PFX 概念
在线程之间分配工作有两种策略:数据并行和任务并行。
当一组任务必须在许多数据值上执行时,我们可以通过让每个线程在一个数据值子集上执行(相同的)一组任务来实现并行化。这就是所谓的数据并行,因为我们是在线程之间分割数据。与此相反,在任务并行时,我们对任务进行分区;换句话说,我们让每个线程执行不同的任务。
一般来说,数据并行在高并行硬件上更容易实现,扩展性也更好,因为它减少或消除了共享数据(从而减少了争用和线程安全问题)。此外,数据并行利用了数据值往往多于离散任务这一事实,增加了并行的潜力。
数据并行也有利于结构化并行,这意味着并行工作单元在程序中的同一位置开始和结束。相比之下,任务并行往往是非结构化的,这意味着并行工作单元可能在程序中分散的地方开始和结束。结构化并行更简单、更不容易出错,而且可以将分区和线程协调(甚至是结果整理)等困难的工作外包给库。
PFX 组件
PFX 包括两层功能,如图 22-1 所示。高层包括两个结构化数据并行应用程序接口:PLINQ 和Parallel 类。较低层包含任务并行类,外加一组额外的构造,以帮助并行编程活动。
图 22-1. PFX 组件
PLINQ 提供了最丰富的功能:它能自动执行并行化的所有步骤,包括将工作划分为任务、在线程上执行这些任务,以及将结果整理为单一的输出序列。 ...
Become an O’Reilly member and get unlimited access to this title plus top books and audiobooks from O’Reilly and nearly 200 top publishers, thousands of courses curated by job role, 150+ live events each month,
and much more.
Read now
Unlock full access