并行处理可以增加您的程序完成的任务数量,从而减少总体处理时间。这些技术有助于我们处理大规模的问题。
在本节中,我们将涵盖以下主题:
- 并行处理简介
- 用于并行处理的 Python Multi Processing 库
- IPython 并行框架
并行处理简介
为了实现并行化,将问题划分为不依赖于其他子单元(或依赖性较小)的子单元至关重要。子单元之间完全独立的问题被称为“令人尴尬的并行”(embarrassingly parallel,也称为易并行问题)。
例如,对数组进行逐元素操作。在这种情况下,操作只需要知道它当前正在处理的特定元素。
在另一种情况下,被划分为子单元的问题必须共享一些数据才能执行操作。由于通信成本的原因,这会导致性能问题。
处理并行程序主要有两种方式:
- 共享内存
在共享内存模式下,子单元可以通过相同的内存空间相互通信。其优点是您不需要显式处理通信,因为这种方法足以从共享内存读取或写入数据。但是,当多个进程同时访问和更改同一内存位置时,就会出现问题。这种冲突可以通过使用同步技术来避免。
- 分布式内存
在分布式内存模式下,每个进程是完全分离的,拥有自己的内存空间。在这种情况下,通信是在进程之间显式处理的。由于通信是通过网络接口进行的,因此与共享内存相比,它的成本更高。
线程是使用共享内存实现并行的一种方式。它们是源自进程的独立子任务,并共享内存。由于 全局解释器锁 的存在,在 Python 中无法使用线程来提高性能。GIL 是 Python 解释器设计中的一种机制,它一次只允许运行一条 Python 指令。通过使用进程代替线程,可以完全避免 GIL 的限制。使用进程有一些缺点,例如进程间通信不如共享内存高效,但它更加灵活且显式。
用于并行处理的 Multi Processing 模块
通过使用标准的 multiprocessing 模块,我们可以通过创建子进程来高效地并行化简单的任务。该模块提供了一个易于使用的接口,并包含一组用于处理任务提交和同步的工具集。
#### Process 和 Pool 类
Process
通过继承 INLINECODE01bbc050,您可以创建一个独立运行的进程。通过扩展 INLINECODE91efc351 方法,您可以初始化资源;通过实现 Process.run() 方法,您可以为子进程编写代码。在下面的代码中,我们将看到如何创建一个打印分配的 ID 的进程:
要生成(spawn)进程,我们需要初始化 Process 对象并调用 INLINECODE3e1d5187 方法。这里 INLINECODE7db3e6aa 将创建一个新进程并调用 Process.run() 方法。
INLINECODEfa40074b 之后的代码将在进程 p 的任务完成之前立即执行。要等待任务完成,您可以使用 INLINECODE4cd89479。
以下是完整的代码:
Python3
CODEBLOCK_6c1780b0
Output:
Pool 类
Pool 类可用于针对不同输入数据并行执行函数。INLINECODEc5a09c90 类会生成一组称为工作进程的进程,并可以使用 INLINECODEc2120bdd 和 INLINECODEbad8cde1 方法提交任务。为了进行并行映射,您应该首先初始化一个 INLINECODE1ce79b8d 对象。第一个参数是工作进程的数量;如果未给出,该数字将等于系统中的核心数。
让我们通过一个示例来看一下。在这个示例中,我们将看到如何传递一个计算数字平方的函数。使用 Pool.map(),您可以将该函数映射到列表,并将函数和输入列表作为…