使用 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