阅读文档,subprocess.call
和subprocess.check_output
都是subprocess.Popen
的使用案例。一个小区别是如果子进程返回非零退出状态,则check_output
会引发Python错误。更大的区别强调了关于check_output
的部分(我加粗了):
整个函数签名基本上与Popen构造函数相同,除了stdout不被允许,因为它在内部使用。所有其他提供的参数都直接传递给Popen构造函数。
那么stdout
是如何“在内部使用”的呢?让我们比较一下call
和check_output
:
call
def call(*popenargs, **kwargs):
return Popen(*popenargs, **kwargs).wait()
check_output
:检查并返回程序执行结果的标准输出。
def check_output(*popenargs, **kwargs):
if 'stdout' in kwargs:
raise ValueError('stdout argument not allowed, it will be overridden.')
process = Popen(stdout=PIPE, *popenargs, **kwargs)
output, unused_err = process.communicate()
retcode = process.poll()
if retcode:
cmd = kwargs.get("args")
if cmd is None:
cmd = popenargs[0]
raise CalledProcessError(retcode, cmd, output=output)
return output
通信
现在我们需要看一下 Popen.communicate
。这样做,我们注意到对于一个管道,communicate
做了几件事情,比返回 Popen().wait()
更花费时间,而 call
则不同。
一方面,communicate
处理 stdout=PIPE
,无论您是否设置了 shell=True
。显然,call
不会这样做。它只让您的 shell 输出任何内容... 这是一个安全风险,正如 Python 在这里描述的那样。
其次,在 check_output(cmd, shell=True)
的情况下(仅有一个管道)... 你的子进程发送到 stdout
的任何内容都将被 _communicate
方法中的一个线程处理。而且,Popen
必须加入该线程(等待它),然后才能等待子进程本身终止!
此外,更微不足道的是,它将 stdout
处理为一个 list
,必须将其连接成一个字符串。
简而言之,即使是最少的参数,check_output
在 Python 进程中花费的时间比 call
要多得多。
subprocess32
模块运行相同的代码,以查看是否存在异常延迟,即旧版本中是否存在错误? - jfssubprocess32
可在 Python 2.7 (posix 系统) 上运行。 - jfs