【问题标题】:Python subprocess check_output much slower then callPython 子进程 check_output 比调用慢得多
【发布时间】:2012-12-12 07:43:29
【问题描述】:

我试图理解为什么会发生这种情况。我正在调用命令以在 Ubuntu 服务器 12.04 上重新启动网络。

快速执行

当我使用以下三种方式之一调用命令时,执行大约需要 0.1 秒:

  1. 直接在终端中
  2. python 脚本使用os.system
  3. python 脚本使用subprocess.call

终端会话:

root@ubuntu:~# time /etc/init.d/networking restart
 * Running /etc/init.d/networking restart
 * Reconfiguring network interfaces...
real    0m0.105s

root@ubuntu:~# time python -c "import os;
> os.system('/etc/init.d/networking restart')"
 * Running /etc/init.d/networking restart
 * Reconfiguring network interfaces...
real    0m0.111s

root@ubuntu:~# time python -c "import subprocess;
> subprocess.call(['/etc/init.d/networking', 'restart'])"
 * Running /etc/init.d/networking restart
 * Reconfiguring network interfaces...
real    0m0.111s

执行缓慢

但是,如果我使用 subprocess.check_output 或 Popen 并尝试读取输出,则需要 23 秒。慢得多。似乎只有当我尝试使用将返回命令输出的函数时才会发生这种巨大的差异。我想了解为什么会发生这种情况,并找到一个解决方案来执行此命令并获得它的输出,而不会花费这么长时间。

终端会话:

root@ubuntu:~# time python -c "import subprocess;
> print subprocess.check_output(['/etc/init.d/networking', 'restart'])"
 * Running /etc/init.d/networking restart
 * Reconfiguring network interfaces...
real    0m23.201s

root@ubuntu:~# time python -c "from subprocess import Popen, PIPE;
> print Popen(['/etc/init.d/networking', 'restart'], stdout=PIPE).stdout.read()"
 * Running /etc/init.d/networking restart
 * Reconfiguring network interfaces...
real    0m23.201s

更新

其中一位 cmets 建议尝试 tee 命令。结果非常有趣。如果使用 tee,则在没有任何 python 参与的终端中,它需要相同的 23 秒。我仍然很好奇为什么,但至少这可能会提供更多关于发生了什么的线索。

root@ubuntu:~# time /etc/init.d/networking restart | tee out.txt
 * Running /etc/init.d/networking restart
 * Reconfiguring network interfaces...
real    0m23.181s

【问题讨论】:

  • 我不知道以下任何一个是否相关(question #10150368question #4940607)但一个答案建议将close_fds=True 添加到 popen 参数
  • subprocess.call() 只是subprocess.Popen(*popenargs, **kwargs).wait()
  • @jwpat7 感谢您的链接。我试过 close_fds=True 它没有任何区别。
  • 执行需要多长时间:networking restart | tee some_file(检查 some_file 是否为空)。试试bufsize=-1 和/或f = TemporaryFile(); check_call(cmd, stdout=f, stderr=STDOUT); f.seek(0); output = f.read()
  • @J.F.Sebastian 这些建议很棒。我在问题中发布了 tee 的结果,输出的文件不是空的,它包含输出。您的临时文件方法效果很好。如果您将其发布为下面的答案,我可以投票。我仍然不明白为什么会这样。

标签: python performance subprocess


【解决方案1】:

以下代码基于 J.F. Sebastian 的出色评论。下面的代码按预期在 0.1 秒内运行,并将命令的输出返回为字符串。

from subprocess import check_call, STDOUT
from tempfile import NamedTemporaryFile

with NamedTemporaryFile() as f:
    check_call(['/etc/init.d/networking', 'restart'], stdout=f, stderr=STDOUT)
    f.seek(0)
    output = f.read()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-08
    • 2016-07-10
    • 2018-02-21
    • 1970-01-01
    • 2019-05-30
    • 2020-02-12
    • 2018-03-10
    • 1970-01-01
    相关资源
    最近更新 更多