subprocess.Popen() 多进程
subprocess.Popen() 用法
subprocess.Popen()主要是用来在 python 中实现多进程程序。例如,在 python 脚本中,我们需要执行另一个 python 脚本,或者执行 shell 命令或者 shell 脚本,这种情况下就要用到 python 的多进程方法了。本文仅介绍 subprocess.Popen() 方法.
subprocess.Popen() 的使用格式:
class subprocess.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)
各个参数的含义:
subprocess.PIPE 可以初始化 stdin, stdout 或 stderr 参数。表示与子进程通信的标准流
subprocess.STDOUT 用于初始化 stderr 参数,表示将错误通过标准输出流输出。
Popen 的属性
子进程结束的判断
首先来看一段代码:
import subprocess as sp
p = sp.Popen(['echo','helloworl.py'], stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE)
print(p.poll())
print('Exit code:', p.returncode)
打印结果如下,在上述代码中我们仅仅创建了一个 Popen 对象,然后开启了子进程,随后通过 poll() 和 returncode 查看子进程的返回码,从结果来看,子进程没有结束主进程就退出了。
None
Exit code: None
下面我们通过读取 stdout 的内容来看看子进程会不会正常结束:
import subprocess as sp
p = sp.Popen(['echo','helloword.py'], stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE)
print((p.stdout.readlines())[0].decode(), end='')
print(p.poll())
print('Exit code:', p.returncode)
结果如下,可以看到,结果仍然是子进程没有结束。
helloword.py
None
Exit code: None
前面说到,wait 会等待子进程结束,那么我们试试执行 wait 看看:
import subprocess as sp
p = sp.Popen(['echo','helloword.py'], stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE)
print(p.poll())
print(p.wait())
print('Exit code:', p.returncode)
结果可以看到,在 wait 之前子进程并没有结束,wait 执行返回的值 0,returncode 也是 0,表明子进程正常执行并结束了。
None
0
Exit code: 0
虽然 wait 可以让子进程正常结束,但是如果缓存中太多数据的话会导致死锁,因此我们采用 communicate:
import subprocess as sp
p = sp.Popen(['echo','helloword.py'], stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE)
output, err = p.communicate()
print(output.decode('gbk'), end='')
print(err.decode('gbk'))
print(p.poll())
print('Exit code:', p.returncode)
结果如下,可见在 communicate 之后,子进程正常执行,缓存中的数据被读取出来,poll 和 returncode 都返回 0,表明子进程已正常结束。output 是子进程执行输出的信息,err 是执行异常时的报错信息,此处可以看到报错信息为空,说明子进程顺利执行,没有错误发生。
helloword.py
0
Exit code: 0
今天发现一个有意思的现象,当 p.stdout.readlines()读取了内容之后,再使用 p.communicate() 读取子进程缓存中的内容,发现后者已经没有内容了,代码如下:
import subprocess as sp
p = sp.Popen(['echo','helloworl.py'], stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE)
print(p.poll())
print('Exit code:', p.returncode)
print((p.stdout.readlines())[0].decode(), end='')
output, err = p.communicate()
print(output.decode('gbk'), end='')
print(err.decode('gbk'))
# p.terminate()
print(p.poll())
print('Exit code:', p.returncode)
结果如下:
None
Exit code: None
helloworl.py
0
Exit code: 0
结果可以看出,p.communicate()没有读取到内容,猜测可能是 p.stdout.readlines() 已经将内容读取出来,因而管道中已经没有内容了,但是前面讲到 p.stdout.readlines()读取了内容之后进程并不能正常结束,只有 p.communicate() 可以让进程正常结束。那么在碰到需要用 p.stdout.readlines()的时候,我们可以采用 terminate() 让进程强制结束。
import subprocess as sp
p = sp.Popen(['echo','helloworl.py'], stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE)
print(p.poll())
print('Exit code:', p.returncode)
print((p.stdout.readlines())[0].decode(), end='')
p.terminate()
print(p.poll())
print('Exit code:', p.returncode)
结果如下:
None
Exit code: None
helloworl.py
0
Exit code: 0
😄
这个必须点赞👍