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服务器进行注册。下面是一个简单的示例服务器:

blob.png

blob.png

而且,在客户端,这是一件简单的事,创造一个“代理”,通过使用代理,看起来像一个标准的Python函数调用。下面是一个简单的示例客户端:

 blob.png

注意:

如果你仅仅想通过本地机器连接该XML-RPC服务器,那么,你可以通过以下方式创建服务器:

 blob.png

并且,在客户端,通过以下方式创建代理:

 blob.png

注意,在服务器中,我们也可以在一个类中显示一个方法。

还有,在我的局域网中,我已经能够运行上面的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执行。例如:

 blob.png

2.创建一个客户端和一个负载均衡的视图。例如:

 blob.png

3.提交多个任务。例如:

 blob.png

4.得到结果。例如:

 blob.png

下面是完整的代码示例:

 blob.png

注意:

  • 本例要求Python在四个独立的过程中并行执行四个函数调用。

  • 因为这些函数调用是在单独的进程中执行,他们避免了Python的GIL冲突(全局解释器锁)。

  • 我们使用默认的调度策略,即“最小负载”策略,来开启集群。对于其他的调度策略,我们可以使用下面的指令来寻找帮助:

 blob.png

也可以参考该链接: http://ipython.org/ipython-doc/dev/parallel/parallel_task.html#schedulers。

3.1 远程机器和引擎

把本来在IPython引擎运行的作业提交到远程机器上,至少在某些情况下,是很容易的。步骤如下:

  • 在远程计算机上启动IPython控制器和引擎。例如:

 blob.png

  • 将远程机器上的文件~/.ipython/profile_default/security/ipcontroller-client.json复制到客户端security/目录下,你将会在本地机器上用到该文件。

  • 当你创建了自己的客户端,使用如下的代码:

 blob.png

但是,把用户名和密码改成远程机器的用户名和密码。

关于利用远程主机进行IPython并行计算的更多信息,请点击:http://ipython.org/ipython-doc/dev/parallel/parallel_process.html#using-the-ipcontroller-and-ipengine-commands。

3.2 并行函数装饰器

你也可以通过使用IPython装饰器来创建一个并行函数,例如:

 blob.png

更多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(全局解释器锁);每一个都有它自己的输入模块;并且,这些进程中的每个模块都有它自己的全局变量。

文档实例。下面是一些更复杂的示例代码:

 blob.png

 blob.png

上面的代码做了以下工作:

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”服务器:

 blob.png

下面是一个用pyzmq实现的“Hello,World”客户端:

 blob.png

如果你在一个会话窗口启动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.我们在一段代码中运行另一段以不同语言编写的代码。在下文的示例代码中,客户端用JavaScript/ 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客户端:

blob.png

blob.png

blob.png

这是Python代理,就像客户端和一个或多个工作进程间的中介:

blob.png

最后,下面是Python工作进程,实际上,它使用lxml来提供XML处理功能:

blob.png

blob.png

注意:

  • 如果我们启动多个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://zeromq.org/bindings:_start.

 

2月15日11:00到13:00网站停机维护,13:00前恢复
iPy智能助手 双击展开
查看更多聊天记录
(Ctrl+回车)换行