Python多进程编程

Python 实现线程式编程的一种简单且有效的模式。但是,这种方法的一个缺陷就是它并不总是能够提高应用程序的速度,因为全局解释器锁(Global Interpreter Lock,GIL)将线程有效地限制到一个核中。如果需要使用计算机中的所有核,那么通常都需通过 对 经常使用 fork 操作来实现,从而提高速度。处理进程组是件困难的事情,因为为了在进程之间进行通信,需要对所有调用进行协调,这通常会使事情变得更复杂。

自 2.6 版本起,Python 包括了一个名为 “多进程(multiprocessing)” 的模块来帮助处理进程。该进程模块的 API 与线程 API 的工作方式有些相似点,但是也存在一些需要特别注意的不同之处。主要区别之一就是进程拥有的一些微妙的底层行为,这是高级 API 永远无法完全抽象出来的。


os.fork 简介

进程和线程在并发性的工作原理方面存在一些明显的差异。在进程执行 fork 时,操作系统将创建具有 ID 的新的子进程,复制父进程的状态(内存、环境变量等)。首先,在我们实际使用进程模块之前,先看一下 Python 中的一个非常基本的 fork 操作。

#!/usr/bin/env python
"""fork example"""
import os

def main():
child_pid = os.fork()
if child_pid == 0:
print "Child Process: PID# %s" % os.getpid()
else:
print "Parent Process: PID# %s" % os.getpid()

if __name__ == "__main__":
main()

下面来看一下进程之间的系统变量传递。

#!/usr/bin/env python
"""A fork that demonstrates a copied environment"""

import os

def main():
os.environ['prefix']="zip"
print "prefix environmental variable set to: %s" % os.environ['prefix']
os.environ['prefix']="tar"
print "prefixenvironmental variable changed to: %s" % os.environ['prefix']
child_pid = os.fork()
if child_pid == 0:
print "Child Process: PID# %s" % os.getpid()
print "Child prefixenvironmental variable == %s" % os.environ['prefix']
else:
print "Parent Process: PID# %s" % os.getpid()
print "Parent prefix environmental variable == %s" % osenviron['prefix']

if __name__ == "__main__":
main()

下面给出了 fork 的输出:

prefix environmental variable set to: zip
prefix environmental variable changed to: tar
Parent Process: PID# 52333
Parent prefix environmental variable == tar
Child Process: PID# 52334
Child prefix environmental variable == tar

在输出中,可以看到 “修改后的” 环境变量 prefix 留在了子进程和父进程中。您可以通过在父进程中再次修改环境变量来进一步测试这个示例,您将看到子进程现在是完全独立的,它有了自己的生命。

注意,子进程模块也可用于 fork 进程,但是实现方式没有多进程模块那么复杂。

下面看一下多进程实用的例子

#!/usr/bin/env python
from multiprocessing import Process
import os
import time

def sleeper(name, seconds):
print 'starting child process with id: ', os.getpid()
print 'parent process:', os.getppid()
print 'sleeping for %s ' % seconds
time.sleep(seconds)
print "Done sleeping"

if __name__ == '__main__':
print "in parent process (id %s)" % os.getpid()
p = Process(target=sleeper, args=('bob', 5))
p.start()
print "in parent process after child process start"
print "parent process about to join child process"
p.join()
print "in parent process after child process join"
print "parent process exiting with id ", os.getpid()
print "The parent's parent process:", os.getppid()

输出如下:

in parent process (id 5245)
in parent process after child process start
parent process about to join child process
starting child process with id: 5246
parent process: 5245
sleeping for 5
Done sleeping
in parent process after child process join
parent process exiting with id 5245
The parent's parent process: 5231

posted @ 2011-09-13 16:45  残夜  阅读(1821)  评论(0编辑  收藏  举报