例解Python:Python编程快速入门践行指南,python多进程编程
Yyds干货库存
加速计算是每个人都想达到的目标。如果你的脚本运行速度比当前运行速度快十倍会怎样?在本文中,我们将学习Python多进程和一个叫做多处理的进程。我们将讨论什么是多进程,它的优势以及如何利用并行编程来提高Python程序的运行时间。
并行性介绍在深入研究Python代码之前,我们必须先讲一下并行计算,这是计算机科学中的一个重要概念。
通常,当你运行Python脚本时,你的代码有时会变成一个进程,而这个进程运行在一个CPU的单核上。但是现代计算机不止一个核心,那么如果可以使用更多的核心进行计算呢?原来你的计算速度会更快。
现在让我们把它作为一个普遍原则,但在本文的后面,我们将看到这并不是普遍适用的。
不需要太多的细节,并行性背后的思想是以一种可以使用多个CPU内核的方式编写代码。
为了使事情变得简单,让我们看一个例子。
并行和串行计算假设你有一个巨大的问题要解决,而你是一个人。你需要计算八个不同数字的平方根。你是做什么的?你没有太多选择。从第一个数字开始,然后计算结果。然后,你和别人继续。
如果你有三个数学很好,愿意帮助你的朋友呢?他们每个人都会计算两个数的平方根,你的工作会更轻松,因为工作量在你的朋友中平均分配。这意味着你的问题会得到更快的解决。
好了,都清楚了吗?在这些例子中,每个朋友代表CPU的核心。第一个例子,整个任务由你依次解决。这叫做串行计算。在第二个例子中,因为您总共使用了四个内核,所以您使用了并行计算。并行计算涉及使用并行进程或在处理器的多个内核之间划分的进程。
并行编程模型我们已经确定了什么是并行编程,但是我们如何使用它呢?正如我们之前所说,并行计算涉及在处理器的多个内核之间执行多个任务,这意味着这些任务是同时执行的。在并行化之前,您应该考虑几个问题。比如有没有其他的优化可以加快我们的计算速度?
现在,让我们理所当然地认为并行化是最合适的解决方案。并行计算有三种主要模式:
完全平行。任务可以独立运行,不需要相互通信。共享内存并行性。进程(或线程)需要通信,因此它们共享一个全局地址空间。消息传递。需要时,进程需要共享消息。在本文中,我们将解释第一个模型,这也是最简单的。
Python中的多进程:基于进程的并行性,在Python中实现并行性的一种方法是使用多处理模块。多重处理模块允许您创建多个进程,每个进程都有自己的Python解释器。因此,Python多进程实现了基于进程的并行。
您可能听说过其他库,比如threading,它也内置于Python中,但是它们之间有重要的区别。多处理模块创建一个新进程,线程化创建一个新线程。
使用多个流程的好处您可能会问,“为什么选择多个流程?”多进程可以通过并行而不是顺序运行多个任务来显著提高程序的效率。一个类似的术语是多线程,但它们是不同的。
进程是加载到内存中运行的程序,不与其他进程共享内存。是线程进程中的一个执行单元。多个线程在一个进程中运行,共享该进程的内存空间。
Python的全局解释器锁(GIL)只允许一个线程在解释器中下次运行,这意味着如果你需要一个Python解释器,你将无法享受多线程的性能优势。这就是为什么在Python中多进程比线程更占优势。多个进程可以并行运行,因为每个进程都有自己的解释器,解释器执行分配给它的指令。此外,操作系统会在多个进程中查看您的程序,并分别进行调度,也就是说,您的程序会在整个计算机资源中占据更大的份额。所以当程序受CPU限制时,多进程速度更快。当程序中有大量I/O时,线程可能会更高效,因为大多数时候,程序都在等待I/O完成。但是,多进程通常效率更高,因为它是同时运行的。
以下是多进程的一些好处:
与线程相比,在处理高CPU密集型任务时更好地利用CPU,子线程的控制更容易编写代码。第一个优势与性能有关。因为多进程创建新的进程,所以您可以通过在其他核心之间分配任务来更好地利用CPU的计算能力。现在大部分处理器都是多核处理器,如果优化代码,可以通过并行计算节省时间。
第二个优势是多线程的可替代性。这不是一个过程,这是有后果的。如果你创建了一个线程,像正常进程一样终止它甚至中断它是很危险的。由于多进程和多线程之间的比较超出了本文的范围,我将单独写一篇文章来讨论多进程和多线程之间的区别。
多进程的第三个好处是容易实现,因为你要处理的任务适合并行编程。
多进程Python介绍我们终于准备好写一些Python代码了!
我们将从一个非常基本的例子开始,我们将用它来说明Python多进程的核心方面。在本例中,我们将有两个流程:
家长经常。父进程只有一个,可以有多个子进程。子进程。这是由父进程生成的。每个子进程也可以有一个新的子进程。我们将使用这个子过程来执行一个函数。这样,父进程可以继续执行。
一个简单的Python多进程示例这是我们将在此示例中使用的代码:
从多重处理导入流程
def bubble_sort(数组):
检查=真
while check==True:
检查=假
对于范围内的I(0,len(array)-1):
if array[i] array[i 1]:
检查=真
temp=array[i]
array[i]=array[i 1]
数组[i 1]=临时
print(数组排序: ,数组)
if __name__==__main__ :
p=进程(target=bubble_sort,args=([1,9,4,5,2,6,8,4]))
开始()
P.join()在这个片段中,我们定义了一个命名的bubble_sort(数组)。这个函数是冒泡排序算法的一个非常简单的实现。如果你不知道它是什么,请不要担心,因为它不重要。要知道的关键是,它是一个能实现某种功能的函数。
我们从多重处理中引入类进程。此类表示将在单独的进程中运行的活动。事实上,您可以看到我们已经传递了一些参数:
Target=bubble_sort,这意味着我们的新进程将运行这个bubble_sort函数args=([1,9,4,52,6,8,4]),这是一个作为参数传递给目标函数的数组。一旦我们创建了process类的实例,我们只需要启动流程。这是通过编写p.start()来实现的。此时,流程开始。
在退出之前,我们需要等待子进程完成它的计算。join()方法等待进程终止。
在这个例子中,我们只创建了一个子流程。正如您可能猜到的,我们可以通过在process类中创建更多的实例来创建更多的子流程。
进程池类如果我们需要创建多个进程来处理更多CPU密集型任务怎么办?我们总是需要显式地开始并等待终止吗?这里的解决方案是使用Pool类。
类池允许您创建一个工作进程池。在下面的例子中,我们将研究如何使用它。这是我们的新例子:
从多处理导入池
导入时间
导入数学
N=5000000
定义立方体(x):
返回math.sqrt(x)
if __name__==__main__ :
使用池()作为池:
result=pool.map(cube,range(10,N))
打印(“程序完成!”)在这个代码片段中,我们有一个只接受整数并返回其平方根的cube(x)函数。很简单吧?
然后,我们创建一个Pool类的实例,而不指定任何属性。默认情况下,Pool类为每个CPU内核创建一个进程。接下来,我们用几个参数运行map方法。
Map方法将cube函数应用于我们提供的iterable对象的每个元素3354。在这个例子中,它是从10到n的所有数字的列表。
这样做最大的好处就是列表上的计算是并行执行的!
Job package joblib是一组工具,可以使并行计算变得更容易。它是一个多进程的通用第三方库。它还提供缓存和序列化功能。要安装joblib软件包,请在终端中使用以下命令:
安装joblib我们可以将前面的示例转换为下面的示例,以便与JobLib一起使用:
从joblib并行导入,延迟
定义立方体(x):
返回x**3
开始时间=时间.性能计数器()
result=Parallel(n_jobs=3)(范围(1,1000)中I的延迟(立方)(I))
完成时间=时间.性能计数器()
打印(f 程序在{完成时间-开始时间}秒内完成)
打印(结果)其实直观的看它的作用。delayed()函数是另一个函数的包装器,用于生成函数调用的“延迟”版本。这意味着它不会在被调用时立即执行该函数。
然后,我们多次调用延迟函数,并传递不同的参数集。例如,当我们将整数1赋给cube函数的延迟版本时,我们不是计算结果,而是分别为函数对象、位置参数和关键字参数生成元组(cube,(1),{})。
我们使用Parallel()创建了引擎实例。当它像以元组列表为参数的函数一样被调用时,实际上会并行执行每个元组指定的作业,在所有作业完成后将结果收集为列表。这里,我们创建了n_jobs=3的Parallel()实例,因此将有三个进程并行运行。
我们也可以直接写元组。因此,上面的代码可以重写为:
result=parallel(n _ jobs=3)((cube,(I,{}) for i in range (1,1000))使用joblib的好处是,我们只需添加一个额外的参数,就可以在多个线程中运行代码:
Result=parallel (n _ jobs=3,prefer= threads )(delayed(cube)(I)for I in range(1,1000))这隐藏了并行运行函数的所有细节。我们只是用了和普通列表理解没有太大区别的语法。
充分利用Python多进程创建多个进程,进行并行计算,并不一定比串行计算更有效。对于CPU密度低的任务,串行计算比并行计算快。因此,知道何时应该使用多进程是非常重要的。这取决于你正在执行的任务。
为了让你相信这一点,让我们看一个简单的例子:
从多处理导入池
导入时间
导入数学
N=5000000
定义立方体(x):
返回math.sqrt(x)
if __name__==__main__ :
#第一种方式,使用多重处理
开始时间=时间.性能计数器()
使用池()作为池:
result=pool.map(cube,range(10,N))
完成时间=时间.性能计数器()
打印(“程序在{}秒内完成-使用多重处理”)。格式(完成时间-开始时间))
打印(-)
#第二种方式,串行计算
开始时间=时间.性能计数器()
结果=[]
对于范围(10,N)中的x:
result.append(cube(x))
完成时间=时间.性能计数器()
打印(“程序在{}秒内完成”)。format (finish _ time-start _ time))此代码片段基于前面的示例。我们在解决同一个问题,就是计算数n的平方根,但是有两种方法。第一个涉及到Python流程的使用,而第二个不涉及。我们使用时间库中的perf_counter()方法来测量时间性能。
在我的电脑上,我得到了这个结果:
python code.py
程序在1.6385094秒内完成-使用多重处理
-
程序在2.7373942999999996秒内完成如你所见,相差不止一秒。所以在这种情况下,多进程比较好。
让我们改变代码中的一些东西,比如N的值。让我们将其减少到N=10000,看看会发生什么。
这是我现在拥有的:
python code.py
程序在0.3756742秒内完成-使用多重处理
-
程序在0.00509840000000003秒内完成发生了什么?现在看来,多流程是个不好的选择。为什么?
与要解决的任务相比,进程间拆分计算带来的开销太大。你可以看到时间性能的差异有多大。
总结多进程如何使用Python中的模块创建运行函数的新进程,如何启动和完成进程,如何使用进程池实现多进程,如何使用第三方库joblib执行多进程。在本文中,我们将通过使用Python多进程来讨论Python代码的性能优化。
首先,我们简要介绍什么是并行计算以及使用它的主要模型。然后,我们开始讨论多流程及其优势。最后,我们看到并行计算并不总是最佳选择,应该使用多处理模块来并行化CPU密集型任务。一如既往,这是一个考虑您所面临的具体问题并评估不同解决方案的利弊的问题。
原创作品来自程,
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。