gpt4 book ai didi

python - subprocess.check_output 与 subprocess.call 的性能

转载 作者:IT老高 更新时间:2023-10-28 20:22:04 34 4
gpt4 key购买 nike

我一直在使用 subprocess.check_output()有一段时间从子进程捕获输出,但在某些情况下遇到了一些性能问题。我在 RHEL6 机器上运行它。

调用 Python 环境是 linux 编译的 64 位。我正在执行的子进程是一个 shell 脚本,它最终通过 Wine 触发一个 Windows python.exe 进程(为什么需要这种愚蠢是另一回事)。作为 shell 脚本的输入,我正在输入一小段 Python 代码,这些代码会传递给 python.exe。

当系统处于中等/高负载(40% 到 70% 的 CPU 利用率)时,我注意到使用 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?

最佳答案

阅读文档,subprocess.callsubprocess.check_output 都是 subprocess.Popen 的用例。一个小的区别是,如果子进程返回非零退出状态,check_output 将引发 Python 错误。关于 check_output 的部分强调了更大的区别(我的重点):

The full function signature is largely the same as that of the Popen constructor, except that stdout is not permitted as it is used internally. All other supplied arguments are passed directly through to the Popen constructor.

那么 stdout 如何“在内部使用”?让我们比较一下 callcheck_output:

调用

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 可以。

一方面,无论您是否设置 shell=Truecommunicate 都会处理 stdout=PIPE。显然,call 没有。它只是让你的 shell 喷出任何东西......使其成为安全风险,as Python describes here .

其次,在 check_output(cmd, shell=True) 的情况下(只有一个管道)...您的子进程发送到 stdout 的任何内容都由 <_communicate 方法中的 em>thread。并且 Popen 必须在额外等待子进程本身终止之前加入线程(等待它)!

另外,更简单的是,它将 stdout 处理为一个 list,然后必须将其连接成一个字符串。

简而言之,即使使用最少的参数,check_output 在 Python 进程中花费的时间也比 call 多得多。

关于python - subprocess.check_output 与 subprocess.call 的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25333537/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com