gre*_*law 24 python linux subprocess wine
我已经使用subprocess.check_output()了一段时间来捕获子进程的输出,但在某些情况下遇到了一些性能问题.我在RHEL6机器上运行它.
调用Python环境是linux编译的64位.我正在执行的子进程是一个shell脚本,最终通过Wine触发Windows python.exe进程(为什么这个愚蠢是另一个故事).作为shell脚本的输入,我在一小段Python代码中输入了传递给python.exe的代码.
虽然系统处于中等/重负载(CPU利用率为40%到70%),但我注意到subprocess.check_output(cmd, shell=True)在check_output命令返回之前,子进程完成执行后,使用会导致显着延迟(最多约45秒).ps -efH在此期间查看输出显示被调用的子进程sh <defunct>,直到它最终返回正常的零退出状态.
相反,使用subprocess.call(cmd, shell=True)在相同的中/重负载下运行相同的命令将导致子进程立即返回而没有延迟,所有输出都打印到STDOUT/STDERR(而不是从函数调用返回).
为什么只有在check_output()将STDOUT/STDERR输出重定向到其返回值时才有这么大的延迟,而不是call()只是将它打印回父代的STDOUT/STDERR?
Jos*_*8th 27
阅读文档,无论是subprocess.call和subprocess.check_output是的用例subprocess.Popen.一个小的区别是,check_output如果子进程返回非零退出状态,将引发Python错误.check_output(我的重点)强调了更大的差异:
完整的函数签名与Popen构造函数的签名大致相同,只是不允许使用stdout,因为它在内部使用.所有其他提供的参数都直接传递给Popen构造函数.
那么如何stdout"内部使用"?让我们比较call和check_output:
def call(*popenargs, **kwargs):
return Popen(*popenargs, **kwargs).wait()
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
现在我们也要看一下Popen.communicate.这样做,我们注意到对于一个管道来说,communicate做一些事情只需要花费更多时间而不是简单地返回Popen().wait(),就像call这样做.
首先,无论你是否设置communicate过程.显然,不是.正如Python在此描述的那样,它只是让你的shell喷出任何东西......这会带来安全风险.stdout=PIPEshell=Truecall
其次,在的情况下check_output(cmd, shell=True)(只是一个管道)......无论你的子进程发送到stdout由加工螺纹的_communicate方法.并且Popen必须加入线程(等待它),然后再等待子进程本身终止!
加,更平凡,它处理stdout为一个list然后必须将其连接成一个字符串.
简而言之,即使使用最少的参数,check_output在Python进程中花费的时间也要多得多call.