14.5 执行其他(非Python)程序
14.5.1 os.system()
>>> import os
>>> result = os.system('ipconfig')
>>> print result
0
system()是一个非常简单的函数,接收字符串形式的系统命令并执行它。
当执行命令的时候,Python的运行是挂起的。当我们执行完成之后,将会以system()的返回值形式给出退出状态,Python的执行也会继续。
通过退出状态显示成功或失败而不是通过输入和/或输出通信。通常的约定是利用退出状态,0表示成功,非0表示其他类型的错误。
14.5.2 os.popen()
>>> import os
>>> f = os.popen('ipconfig')
>>> data = f.readlines()
>>> for d in data:
... print d
...
Windows IP Configuration
Ethernet adapter Local Area Connection:
Connection-specific DNS Suffix . : cn.kodak.com
IP Address. . . . . . . . . . . . : 150.245.167.42
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . : 150.245.167.254
>>>
popen()函数是文件对象和system()函数的结合。它可以建立一个指向那个程序的单向连接,然后像访问文件那样访问这个程序。如果程序要求输入,那么你要用'w'模式写入那个命令来调用popen()。你发给程序的数据会通过标准输入接收到。那么当它写入标准输出的时候,你就可以通过类文件句柄使用熟悉的file对象read*()方法来读取输入。
14.5.3 os.fork()、os.exec*()、os.wait*()
ret = os.fork() #产生两个进程,都返回
if ret ==0: #子进程返回的PID是0
child_suite #子进程的代码
else: #父进程返回是子进程的PID
parent_suite #父进程的代码
fork()采用成为进程的单一执行流程控制,如果你喜欢的话,可称之为创建“岔路口”。
调用fork()的原始进程称为父进程,而作为该调用结果新创建的进程则称为子进程。当子进程返回的时候,其返回值永远是0;当父进程返回时,其返回值永远是子进程的进程标识符(又称进程ID,或PID)(这样父进程就可以监控所有的子进程了)PID(process ID)也是唯一可以区分它们的方式。
在子进程的代码中,我们可以调用任何exec*()函数来运行完全不同的程序,或者一个程序中的其他的函数(只要子进程和父进程用不同的路径执行)。普遍做法是让子进程做所有的脏活,而父进程耐心等来子进程完成任务,或继续进行,稍后再来检查进程是否正常结束。
当子进程完成执行,还没有被收获的时候,它进入了闲置状态,变成了著名的僵尸进程。在系统中,应该尽量把僵尸进程的数目降到最少,因为在这种状态下的子进程仍保留着在存活时期分配给它们的系统资源,而这些资源只能在父进程收获它们之后才能释放掉。
调用wait()会挂起执行(比如waits()),直到子进程(其他的子进程)正常执行完毕或通过信号终止。wait()将会收获子进程,释放所有的资源。waitpid()具有和wait()相同的功能,但是多了一个参数PID(指定要等待子进程的进程标识符),以及选项。
14.5.4 os.spawn*()
函数spawn*()家族和fork、exec*()相似,因为它们在新进程中执行命令;然而,你不需要分别调用两个函数来创建进程,并让这个进程执行命令。你只需要调用一次spawn*()家族。
14.5.5 subprocess模块
subprocess其中有一个类叫Popen,集中了大部分面向进程的函数。同样也有名为call()的便捷函数,可以轻易地取代了os.system()。