Python 中的线程与进程(二)

使用 subprocess 模块管理进程

  上篇针对进程的创建和终止做了一些说明,但是,这些仅仅是基本的进程管理函数,无法满足复杂的需求。因此,Python提供了subporcess模块进程高级的进程管理。subprocess可以调用外部的系统命令创建新的子进程,同时连接到子进程的input/output/error管道上,并得到子进程的返回值。subprocess模块中提供了一个类和两个实用函数来管理进程,下面进行分别介绍

1 使用Popen类管理进程

  subprocess模块中高级进程的管理能力来自于Popen来的灵活使用,这源于该类中函数原型的丰富参数。

class Popen(args, bufsize = 0, executable = None, stdin = None, stdout = None, stderr = None, preexec_fn = None, close_fds = False, shell = False, cwd = None, env = None, universal_newlines = False, startupinfo = None, creationflags = 0)

  其中args参数为要执行的外部程序。其值可以使字符串或者序列。除此之外,其他的类参数都有默认值,可以根据需要进行修改。

  例子:演示使用Popen类的方法

import subporcess

pingP = subprocess.Popen(args = 'ping -c 4 www.sina.com.cn', shell = True)
pingP.wait()
print pingP.pid
print pingP.returncode


root@wpeng-desktop:/# python sh02.py PING cernetnews.sina.com.cn (121.194.0.239) 56(84) bytes of data. 64 bytes from 121.194.0.239: icmp_seq=1 ttl=52 time=2.43 ms 64 bytes from 121.194.0.239: icmp_seq=2 ttl=52 time=1.00 ms 64 bytes from 121.194.0.239: icmp_seq=3 ttl=52 time=1.48 ms 64 bytes from 121.194.0.239: icmp_seq=4 ttl=52 time=1.02 ms --- cernetnews.sina.com.cn ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 15036ms rtt min/avg/max/mdev = 1.001/1.486/2.439/0.583 ms 2230 0

  上面是程序代码和我电脑的输出,代码中Popen的第二个参数为shell的值。在Linux下,当shell为“False“时,Popen会调用os.execvp来执行对应的程序,而shell为True时,如果命令为字符串,Popen直接调用系统shell来执行指定的程序。如果命令是一个序列,则其第一项是定义命令字符串,其他项为命令的附加参数。

  从输出可以看出,代码产生一个子进程并执行args中指定的命令,然后继续执行下面的语句。如果上面代码不加pingP.wait(),由于网络延迟,会使得在打印了进程ID和返回值后才输出外部命令的结果。

root@wpeng-desktop:/# python sh02.py
2247
None
root@wpeng-desktop:/# PING cernetnews.sina.com.cn (121.194.0.239) 56(84) bytes of data.
64 bytes from 121.194.0.239: icmp_seq=1 ttl=52 time=1.17 ms
64 bytes from 121.194.0.239: icmp_seq=2 ttl=52 time=1.02 ms
64 bytes from 121.194.0.239: icmp_seq=3 ttl=52 time=1.13 ms
64 bytes from 121.194.0.239: icmp_seq=4 ttl=52 time=0.899 ms

--- cernetnews.sina.com.cn ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 15029ms
rtt min/avg/max/mdev = 0.899/1.058/1.173/0.107 ms

  上面None表示次子进程还没有终止。

  子进程创建以后其标准输出 标准输入 标准错误处理都和原进程没有关系。如果需要管理子进程的输入和输出,可以改变Popen类中的stdin stdout stderr等类的参数。在Popen的类参数中,stdin stdout stderr分别用来指定程序标准输入 标准输出和标准错误的处理器,其值可以为‘PIPE‘,文件描述符和'None'等,默认是“None“

import subporcess

pingP = subprocess.Popen(args = 'ping -c 4 www.sina.com.cn', shell = True, stdout = subprocess.PIPE)
pingP.wait()
print pingP.stdout.read()
print pingP.pid
print pingP.returncode

  在获取输出结果后,pingP.stdout成为一个可读的文件对象,可以使用相应的文件操作函数来读取。

  虽然上面代码和第一个代码输出相同,但是如果你把print pingP.stdout.read()用#注释掉,会发现不同之处,不妨试试把~

root@wpeng-desktop:/# python sh02.py
2273
0

    另一种方法时使用Popen提供的communicate方法,该方法为p.communicate([input]),通过将input中提供的数据发送给进程的标准输入,与子进程进行通信。数据一旦发送,方法就会等待进程终止,同时收集标准输出上接收到的输出和标准错误。返回值是一个元组(stdout,stderr)。

  子进程的文本流控制

    子进程的标准输入,标准输出和标准错误也可以通过如下属性表示:

pingP.stin
pingP.stdout
pingP.stderr

 

我们可以在Popen()建立子进程的时候改变标准输入、标准输出和标准错误,并可以利用subprocess.PIPE将多个子进程的输入和输出连接在一起,构成管道(pipe):

import subprocess
child1 = subprocess.Popen(["ls","-l"], stdout=subprocess.PIPE)
child2 = subprocess.Popen(["wc"], stdin=child1.stdout,stdout=subprocess.PIPE)
print child2.stdout.read()

subprocess.PIPE实际上为文本 流提供一个缓存区。child1的stdout将文本输出到缓存区,随后child2的stdin从该PIPE中将文本读取走。child2的输出文本也 被存放在PIPE中,直到communicate()方法从PIPE中读取出PIPE中的文本。

要注意的是,communicate()是Popen对象的一个方法,该方法会阻塞父进程,直到子进程完成。

 

我们还可以利用communicate()方法来使用PIPE给子进程输入:

import subprocess
child = subprocess.Popen(["cat"], stdin=subprocess.PIPE)
child.communicate("bupt")

我们启动子进程之后,cat会等待输入,直到我们用communicate()输入"vamei"。

 

通过使用subprocess包,我们可以运行外部程序。这极大的拓展了Python的功能。如果你已经了解了操作系统的某些应用,你可以从Python中直接调用该应用(而不是完全依赖Python),并将应用的结果输出给Python,并让Python继续处理。shell的功能(比如利用文本流连接各个应用),就可以在Python中实现。

2  调用外部系统命令

  subprocess还提供两个使用函数用来直接调用外部系统命令:call(), check_all()。两者是对上面Popen类构造函数使用方法的简化。其参数列表和Popen构造函数的参数列表是一样的。call会直接调用命令生成子进程,并且等待子进程结束,然后返回子进程的返回值。如果要执行一个命令,但又不需要捕捉他的输入或者以其他方式控制它,可以调用这个函数。check_all和call最大的区别是:如果返回值不为0,出发CallProcessError异常,返回值保存在这个异常对象的returncode属性中。

3  Popen()函数返回的Popen对象p具有的一些方法和属性

p.kill()p.communication([input])
p.send_signal(signal)
p.poll()
p.wait()
p.pid()
p.terminate()
p.returncode()
p.stdin, p.stdout, p.stderr

总结:

subprocess.Popen()
Popen.wait()
subprocess.PIPE
Popen.communicate()subprocess.call()
subprocess.check_all()

 

有个不错的文章推荐一下: http://www.cnblogs.com/vamei/archive/2012/09/23/2698014.html

posted @ 2013-03-31 17:14  业精于勤荒于嬉  阅读(583)  评论(0编辑  收藏  举报