Python子进程check_output比调用慢得多

时间:2012-12-12 07:43:30

标签: python performance subprocess

我试图理解为什么会这样。我正在调用一个命令来重启Ubuntu服务器12.04上的网络。

快速执行

当我使用以下三种方法之一调用命令时,执行时间约为0.1秒:

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

    终端会议:

    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
    

    更新

    其中一条评论建议尝试使用tee命令。结果非常有趣。在没有任何python参与的终端中,如果使用T恤,它需要相同的23秒。我仍然很好奇为什么,但至少这可能会给出更多有关正在发生的事情的线索。

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

1 个答案:

答案 0 :(得分:9)

以下代码基于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()