原标题:Python多进程:有例子的教程
Python部落组织翻译,禁止转载,欢迎转发
摘要:本文档是一篇介绍、引导性的文章,介绍了如何在Python中怎样使用多个不同的技术,例如,XML-RPC, IPython parallel processing, and Erlang+Erlport,运行多进程、并行处理以及分布式程序。
1 引言--一些选择和备选方法
本文档针对在Python中实现多进程的几种方法进行了测试,尝试提供一些指导,何时用这些不同的方法是恰当的、有用的,何时是不恰当的。
1.1 目的
我们都拥有多核的机器。很容易想象的到,一个家庭中,有多种类型的电脑和设备通过以太网或者无线方式连接到局域网。这些设备,大部分都是多核的。然而,设备大部分的能力是浪费的,许多的核处理器被闲置。
既然如此,我们的机器为什么还要配置这么多无用的核处理器呢?因为Intel和AMD必须要竞争,为了达到竞争目的,必须要提供给我们看似处理更快的机器。他们不能提供更多的周期(每秒),因为,如果他们这样做了,我们的机器会溶解。所以,他们提供额外的核处理器。机器包含的晶体管数量上升,并且,穆尔定律(在技术上)认为是可以的。但是,对于大多数人,机器的大部分能力被闲置了。
说够了…在本文档中讨论的替代品和选项都是为了解决这个问题。我们正在寻找有用的工具。我们需要学习如何更充分地使用这些机器,以便明年我们可以证明购买另一台有更多核处理器的机器,以增加我们的家庭网络。
我编写这份文档的核心目标是,鼓励更多的人编写软件,使这些机器和内核投入工作。
同时,注意 Larry Wall提出的三个编程美德,特别是:
焦躁:当电脑变得懒惰的时候,你感到愤怒。这让你写的程序不只是对你的需求作出反应,实际上还预期电脑作出反应,或者至少假装作出有反应。
详情请点击: http://threevirtues.com/
1.2 备选方法--综述
XML-RPC--通过网络远程程序调用:
https://docs.python.org/2/library/xmlrpclib.html#module-xmlrpclib
https://docs.python.org/2/library/simplexmlrpcserver.html#module-SimpleXMLRPCServer
https://docs.python.org/2/library/docxmlrpcserver.html#module-DocXMLRPCServer
Python标准库里的多线程模块-- https://docs.python.org/2/library/multiprocessing.html#module-multiprocessing
PP(并行Python)模块 -- http://www.parallelpython.com/
IPython中的并行编程 -- http://ipython.org/ipython-doc/dev/parallel/index.html
使用Erlang进程池的并行处理过程,其中,每一个进程池都包含一个Python程序
基于ZeroMQ和ZeroMQ的Python接口的并行处理消息 -- (1) http://zeromq.org/;(2)http://zeromq.org/bindings:python
1.3 本文档使用的方法
对于上述的每一个选择,我尽量包括:(1)适宜的(和不适宜的)用途;(2)可能使用的情况;(3)一些操作实例;和一些代码示例。
注意,我们将特别关注一个特定的多进程编程模式。我们想有一个设计,其中(1)有多个服务器;(2)有多个客户;(3)任何客户端可以提交任务(功能调用),任何可用的服务器可以对其进行评估。你可能会使用这种模式,如使用一个服务器(进程)池,客户可以提交(通常是计算密集型)函数调用。
2 XML-RPC
XML-RPC是一个简单、容易的方法来获取分布式处理。有了它,你可以要求在远程的机器上调用一个Python进程函数,并且,函数的执行结果会反馈给你。
我们将使用Python标准库的XML-RPC模块。
在服务器端,我们实现了常规的Python函数,然后用一个XML-RPC服务器进行注册。下面是一个简单的示例服务器:
而且,在客户端,这是一件简单的事,创造一个“代理”,通过使用代理,看起来像一个标准的Python函数调用。下面是一个简单的示例客户端:
注意:
如果你仅仅想通过本地机器连接该XML-RPC服务器,那么,你可以通过以下方式创建服务器:
并且,在客户端,通过以下方式创建代理:
注意,在服务器中,我们也可以在一个类中显示一个方法。
还有,在我的局域网中,我已经能够运行上面的XML-RPC脚本。事实上,我在我的其中一个台式机上运行服务器,并且,在我的Android智能手机使用qpython,我通过WiFi从客户端连到了服务器。关于qpython的更多信息见: http://qpython.com/.
3 IPython并行计算
这里有参考文档: http://ipython.org/ipython-doc/dev/parallel/index.html
一个安装Python、IPython、SciPy和Numpy等软件的简单方法就是安装Anaconda工具包。你可以参考以下链接: http://www.continuum.io/和https://store.continuum.io/cshop/anaconda/。
我们想知道如何提交并行执行的任务。下面是关于如何做到这一点的指令:
1.创建集群。使用IPython并行处理的ipcluster执行。例如:
2.创建一个客户端和一个负载均衡的视图。例如:
3.提交多个任务。例如:
4.得到结果。例如:
下面是完整的代码示例:
注意:
本例要求Python在四个独立的过程中并行执行四个函数调用。
因为这些函数调用是在单独的进程中执行,他们避免了Python的GIL冲突(全局解释器锁)。
我们使用默认的调度策略,即“最小负载”策略,来开启集群。对于其他的调度策略,我们可以使用下面的指令来寻找帮助:
也可以参考该链接: http://ipython.org/ipython-doc/dev/parallel/parallel_task.html#schedulers。
3.1 远程机器和引擎
把本来在IPython引擎运行的作业提交到远程机器上,至少在某些情况下,是很容易的。步骤如下:
在远程计算机上启动IPython控制器和引擎。例如:
将远程机器上的文件~/.ipython/profile_default/security/ipcontroller-client.json复制到客户端security/目录下,你将会在本地机器上用到该文件。
当你创建了自己的客户端,使用如下的代码:
但是,把用户名和密码改成远程机器的用户名和密码。
关于利用远程主机进行IPython并行计算的更多信息,请点击:http://ipython.org/ipython-doc/dev/parallel/parallel_process.html#using-the-ipcontroller-and-ipengine-commands。
3.2 并行函数装饰器
你也可以通过使用IPython装饰器来创建一个并行函数,例如:
更多IPython远程函数装饰器信息,请点击: http://ipython.org/ipython-doc/dev/parallel/parallel_multiengine.html#remote-function-decorators。
4 Python标准库中的多进程模块
Python标准库中包括多进程模块。对于创建和运行由Python实现的多线程,并且,利用队列和管道(也在多进程模块)实现进程间的通信,该模块(它实际上是一个Python包或一个像模块的库)包含了一些适当的支持。你可以在这里了解更多该模块的信息: https://docs.python.org/2/library/multiprocessing.html
要知道,多进程模块创建单独的操作系统进程。每一个进程都在自己的内存空间运行;每一个都有自己的Python解释器;每一个都有自己的GIL(全局解释器锁);每一个都有它自己的输入模块;并且,这些进程中的每个模块都有它自己的全局变量。
文档实例。下面是一些更复杂的示例代码:
上面的代码做了以下工作:
1.创建一些进程(类进程的实例)并为每个进程创建一个队列(类队列的实例)。
2.启动进程。
3.等待用户点击回车键。这给了用户时间来查看单独的进程是否已创建。在Linux系统中,我使用htop和top来查看进程。在MS Windows中,你应该使用 Task Manage来查看进程。
4.调用process.join(),等待进程完成。
5.获取并打印每一个进程放入队列中的内容。
使用多进程模块的优点:
对于CPU密集型的计算,你将能够并行的、充分的利用多核和多CPU。这是因为每个进程都有自己的Python解释器和自己的GIL(全局解释器锁)。
对于输入/输出绑定的过程,您还应该能够从并发中获得速度。
因为每个进程独立运行在它自己的内存空间中,对于彼此值跨步的可能性,您的进程将更安全。然而,多进程模块提供了同步原语(例如,类multiprocessing.Lock)和利用进程提供共享内存的能力(类multiprocessing.Array),如果你真的想这样的问题。
5 pp -- 并行Python
在这里,有关于并行Python的信息:http://www.parallelpython.com/。
下面是 Parallel Python网站上的一些描述:
PP是Python的一个模块,提供对SMP(多处理器或核心系统)和集群(通过网络连接的计算机)上的Python代码并行执行的机制。
它易于安装,易于和其他Python软件集成。
PP是一个开源的、跨平台的纯Python编写的模块。
特性:
在SMP和集群上,并行执行Python代码
易于理解和实现基于作业的并行化技术(易于将串行应用程序转换为并行)
自动检测最佳配置(默认情况下,运行进程的数目被设置为有效的处理器的数量)
动态进程分配(在运行时可以改变工作进程的数量)
低开销完成后续具有相同功能的任务(透明缓存实现,以减少开销)
动态负载均衡(在进程运行时进行任务的分配)
容错性(如果一个节点失效,任务被重新安排到其他节点)
自动发现计算资源
计算资源的动态分配(自动发现和故障容错的结果)
基于SHA的网络连接身份验证
跨平台的可移植性和互操作性(Windows、Linux、Unix、Mac OS X)
跨层次的可移植性和互操作性(x86、x86-64,等)
开放源代码
提供的分布式的样例运行良好。但是,这个项目似乎并不十分活跃。
6 ZeroMQ与zmq/pyzmq
下面是一个引述:
ØMQ 一言难尽。
ØMQ(也称ZeroMQ,0mq,或ZMQ)看起来像一个嵌入的网络库,也像一个并发框架。它提供了携带原子信息的套接字,在进程间、进程内部、TCP以及组播间进行传播。你可以用多种模式多对多的连接套接字,比如,扇出模式,发布/订阅模式,任务分发模式,请求/应答模式。它的速度足够快,足够成为集群产品的结构。它的异步输入/输出模式为您提供了可扩展的多核应用程序,内置异步消息处理任务。它有一个语言接口的评分,运行在大多数操作系统中。ØMQ来源于imatix,是lgplv3开源的。 [Pieter Hintjens; http://zguide.zeromq.org/page:all]。
pyzmq,它提供了zmq,是ZeroMQ的Python绑定。
注意,ZeroMQ是底层的IPython并行。因此,可以认为IPython并行计算是ZeroMQ高水平包装的结晶。
对于ZeroMQ,有许多好的用不同语言编写的实例。为了获得这些实例,你需要下载ZeroMQ指南(https://github.com/imatix/zguide.git),然后,看(对于我们的Python程序员)zguide/examples/Python.
为了使用pyzmq和运行它的实例,你需要安装:
ZeroMQ -- http://zeromq.org/
ZeroMQ的Python绑定 -- http://zeromq.org/bindings:python 你还可以在包索引找到它:https://pypi.python.org/pypi/pyzmq
至于我的python测试例子,我用Anaconda Python分布,它支持ZMQ。
我们应该注意,ZeroMQ,就像Erlang语言做的那样,我们的程序在一些场景上使用了Actor模型。这是Actor模型的场景:(1)我们创建不共享(在内存中)资源的单独进程,(2)我们通过发送消息和在消息队列等待来进行通信。相对于Actor模型,ZeroMQ与Erlang的不同体现在以下方面:
在Erlang中,进程在Erlang内部;在ZeroMQ中,不同的是,进程是操作系统进程。因此,与Erlang相比,ZeroMQ中的进程占有更大的比重,启动和停止更慢。然而,需要注意的是,当我们利用Erlang端口或者Erlport从Erlang中调用Python代码时,事实上,我们创建了单独的操作系统进程。
开启ZeroMQ进程的方法之一是在shell(例如bash)命令行。我可以想象,从Python代码中启动多个进程使用subprocess模块或在Node.js代码使用子过程(child_process)模块。但是,在Erlang中,启动数百个并发进程是合理的,在ZeroMQ中,我们不太可能想这样做。
在Erlang中,每个进程都有一个标识,我们发送给每个进程发送信息;在Erlang中,队列是匿名的。在ZeroMQ中,队列有一个标识,我们将消息发送到队列,从队列接收消息;在ZeroMQ中,进程是匿名的,而且,事实上,我们的代码往往不知道一个队列的尽头连接了多少进程。
6.1 Hello world 服务器和客户端
下面是一个用pyzmq实现的“Hello,World”服务器:
下面是一个用pyzmq实现的“Hello,World”客户端:
如果你在一个会话窗口启动hwserver.py,在另一个窗口启动hwclient.py,你会看到服务器和客户端在各自的窗口进行互相回复。
然而,如果你开启一个hwserver.py实例,多个hwclient.py实例,你会发现,在各自通信时,会出现很长的延迟。这是因为多个客户在一台服务器上等待。注意到,服务器上有延时语句(time.sleep(1))。我们的下一个挑战是在多个进程中运行服务器,这样,多个客户的负载将在多个服务器上平衡。我们可以使用IPython多进程来处理。但是,ZeroMQ本身也有多种类似的实现方法。例如,该文档 A Load Balancing Message Broker(负载均衡消息代理)。
6.2 ZeroMQ中的多处理器和混合语言编程
使用ZeroMQ最大的优点就是可以用不同的语言写不同的进程。例如,我们可以,利用Node.js写一个进程来发送消息,用Python写另一个进程来请求服务。
在这个例子中,我们将使用ZeroMQ实现(至少)两点:
1.我们在一段代码中运行另一段以不同语言编写的代码。在下文的示例代码中,客户端用Java/ Node.js编写,我们使用Python编写的代码来请求服务。这为我们提供了一种可供使用的服务方式,例如,在lxml XML包或在SciPy和NumPy数值计算以及科学计算软件包。
2.我们可以启动多个服务器或工作进程,无论是什么,都可以实现负载均衡。通过增加承受负荷,这可以帮助我们提高效率,同时避免Python中的GIL(全局解释器锁)问题,该问题是:在任何一个时间,只允许一个线程执行Python代码。(更多关于这个问题的研究:https://wiki.python.org/moin/GlobalInterpreterLock.)
调试 -- 一些提示:
你可以在Python代码中使用print输出信息来跟踪代码执行过程。
根据你的代码结构,你可能会考虑实现一个装饰器,跟踪装饰器函数的进入和退出功能。关于装饰器,你可以在这里寻求帮助: http://www.davekuhlman.org/python_book_01.html#decorators-and-how-to-implement-them.
Python调试器pdb很好用。事实上,我通常使用ipdb(https://pypi.python.org/pypi/ipdb)。你会考虑在一个单独的窗口/会话中运行该模块进行调试,以便调试命令和结果与其他输出不混合.
6.2.1 一个简单的轮转负载分布
在我们的例子中,Node.js模块将多个请求以ZeroMQ“代理”消息的形式进行整合,通过Python工作模块将这些请求发送出去。如果我们启动多个工作进程,这些请求将以轮转的方式转发给一个或另一个工作进程。
下面是我们的Node.js客户端:
这是Python代理,就像客户端和一个或多个工作进程间的中介:
最后,下面是Python工作进程,实际上,它使用lxml来提供XML处理功能:
注意:
如果我们启动多个Node.js进程,上面的代码可以同时处理多个客户。
我用Node.js和Python写这个实例。但是,我们也可以使用其他的编程语言来实现ZeroMQ之间的通讯。ZeroMQ支持的语言:C, PHP, Python, Lua, Haxe, C++, C#, Common Lisp, Delphi, Erlang, F#, Felix, Haskell, Java, Objective-C, Ruby, Ada, Basic, Clojure, Go, Haxe, Node.js, ooc, Perl, and Scala.
英文原文:http://www.davekuhlman.org/python_multiprocessing_01.html
译者:血杀令
了解野狗,请点击阅读原文。返回搜狐,查看更多
责任编辑: