首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Python 多处理和并行编程指北

加速计算是每个人都想实现的目标。如何让你当前的脚本运行时间快十倍?在本文中,我们将了解 Python 多处理和一个名为multiprocessing的库. 我们将讨论什么是多处理、它的优势,以及如何通过使用并行编程来提高 Python 程序的运行时间。

并行简介

在我们深入 Python 代码之前,我们必须先谈谈并行计算,这是计算机科学中的一个重要概念。

通常,当你运行一个 Python 脚本时,你的代码在某个时候变成了一个进程,并且这个进程在你的 CPU 的一个核心上运行。但是现代计算机有不止一个核心,那么如果你可以使用更多核心进行计算呢?事实证明你的计算会更快。

我们暂时将此作为一般原则,但稍后,在本文中,我们将看到这并非普遍适用。

无需深入了解太多细节,并行化背后的理念是以可以使用 CPU 多核的方式编写代码。

为了使事情更容易,让我们看一个例子。

并行和串行计算

想象一下,你有一个巨大的问题需要解决,而你是一个人。你需要计算八个不同数字的平方根。好吧,你没有太多选择,从第一个数字开始,然后计算结果。然后,继续计算其他的。

如果你有三个擅长数学的朋友愿意帮助你怎么办?他们每个人都会计算两个数字的平方根,你的工作会更容易,因为工作量在你的朋友之间平均分配。这意味着你的问题将得到更快的解决。

在这些示例中,每个朋友代表 CPU 的一个核心。在第一个示例中,整个任务由你按顺序解决。这称为串行计算。在第二个示例中,由于你总共使用了四个内核,因此你使用的是并行计算。并行计算涉及使用并行进程或在处理器中的多个内核之间划分的进程。

并行编程模型

我们已经确定了什么是并行编程,但是我们如何使用它呢?我们之前说过,并行计算就是在处理器的多个核心之间执行多个任务,也就是这些任务是同时执行的。在进行并行化之前,你应该考虑几个问题。例如,是否有任何其他优化可以加快我们的计算速度?

现在,让我们想当然地认为并行化是最适合你的解决方案。并行计算主要有三种模型:

完美平行。任务可以独立运行,不需要相互通信。

共享内存并行性。进程(或线程)需要通信,因此它们共享一个全局地址空间。

消息传递。进程需要在需要时共享消息。

在本文中,我们将说明第一个模型,这也是最简单的。

Python 多处理:Python 中基于进程的并行

在 Python 中实现并行的一种方法是使用多处理模块。multiprocessing模块允许创建多个进程,每个进程都有自己的 Python 解释器。出于这个原因,Python 多处理实现了基于进程的并行性。

你可能听说过其他库,例如threading,它们也是 Python 内置的,但它们之间存在重要区别。multiprocessing模块创建新进程,同时threading创建新线程。

在下一节中,我们将了解使用多处理的优势。

使用多重处理的好处

以下是多处理的一些好处:

在处理高 CPU 密集型任务时更好地使用 CPU

与线程相比,对孩子的控制更多

易于编码

第一个优势与性能有关。由于多处理会创建新进程,因此可以通过将任务分配给其他内核来更好地利用 CPU 的计算能力。现在大多数处理器都是多核处理器,如果你优化代码,可以通过并行解决计算来节省时间。

第二个优势着眼于多处理的替代方法,即多线程。虽然线程不是进程,但这是有其后果的。如果创建了一个线程,那么像处理正常进程那样杀死它甚至中断它是很危险的。

多处理的第三个优点是它很容易实现,因为要处理的任务适合并行编程。

Python 多处理入门

从一个非常基本的示例开始,我们将使用它来说明 Python 多处理的核心方面。在这个例子中,我们将有两个进程:

父进程。只有一个父进程,可以有多个子进程。

子进程。这是由父进程产生的。每个孩子也可以有新的孩子。

我们将使用child进程来执行某个功能。这样, parent就可以继续执行了。

一个简单的 Python 多处理示例

这是我们将用于此示例的代码:

在这段代码中,我们定义了一个名为bubble_sort(array)的函数. 这个函数是冒泡排序算法的一个非常简单的实现。如果不知道它是什么,不要担心,因为它并不那么重要。要知道的关键是它是一个可以完成一些工作的函数。

进程类

从multiprocessing我们导入类Process。此类表示将在单独进程中运行的活动。实际上,可以看到我们传递了一些参数:

target=bubble_sort,这意味着我们的新进程将运行bubble_sort功能

args=([1,9,4,52,6,8,4],),这是作为参数传递给目标函数的数组

一旦我们为 Process 类创建了一个实例,我们只需要启动该进程。这是通过写p.start()来完成的。此时,进程开始。

在我们退出之前,我们需要等待子进程完成它的计算。join()方法等待进程终止。

在这个例子中,我们只创建了一个子进程。你可能猜到了,我们可以通过在Process类中创建更多的实例来创建更多的子进程。

池类

如果我们需要创建多个进程来处理更多 CPU 密集型任务怎么办?我们是否总是需要明确地开始并等待终止?这里的解决方案是使用Pool类。

类Pool允许创建一个工作进程池,在下面的示例中,我们将看看如何使用它。这是我们的新例子:

在这段代码中,我们有一个cube(x)函数,它只接受一个整数并返回它的平方根。

然后,我们创建Pool类的一个实例,不指定任何属性。池类默认为每个 CPU 内核创建一个进程。接下来,我们运行带有几个参数的map方法。

map方法将函数应用于我们提供的可迭代对象的每个元素——在本例中,它是从10到N的每个数字的列表。

这样做的巨大优势是列表上的计算是并行完成的!

充分利用 Python 多处理

创建多个进程并进行并行计算并不一定比串行计算更高效。对于低 CPU 密集型任务,串行计算比并行计算更快。出于这个原因,了解何时应该使用多处理很重要——这取决于正在执行的任务。

为了证明这一点,让我们看一个简单的例子:

此代码段基于前面的示例。我们正在解决同一个问题,即计算数字N的平方根,但是有两种方法。第一个涉及 Python 多处理的使用,而第二个则没有。我们正在使用time库中的perf_counter()方法来测量时间性能。

在我的笔记本电脑上,我得到了这个结果:

如上,相差超过一秒。所以在这种情况下,多处理更好。

让我们改变代码中的一些东西,比如 N的值。让我们把它降低到N=10000看看会发生什么。

这就是我现在得到的:

发生了什么?看来多处理现在是一个糟糕的选择。为什么?

与解决的任务相比,通过在进程之间拆分计算而引入的开销太多了。可以看到在时间性能方面有多大差异。

结论

在本文中,我们讨论了使用 Python 多处理对 Python 代码进行性能优化。

首先,我们简要介绍了什么是并行计算以及使用它的主要模型。然后,我们开始谈论多处理及其优势。最后,我们看到并行化计算并不总是最佳选择,multiprocessing模块应该用于并行化 CPU 密集型任务。与往常一样,这是考虑你面临的具体问题并评估不同解决方案的优缺点的问题。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20230301A00U1Q00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券