Python子进程模块比命令慢得多(不建议使用)

时间:2012-06-04 21:48:13

标签: python performance command subprocess

所以我写了一个脚本,在命令行上使用nc访问一堆服务器,最初我使用的是Python命令模块并调用commands.getoutput(),脚本运行大约45秒。由于命令已弃用,我想将所有内容更改为使用子进程模块,但现在脚本需要2m45s才能运行。任何人都知道为什么会这样?

我之前的所作所为:

output = commands.getoutput("echo get file.ext | nc -w 1 server.com port_num")

现在我有

p = Popen('echo get file.ext | nc -w 1 server.com port_num', shell=True, stdout=PIPE)
output = p.communicate()[0]

提前感谢您的帮助!

2 个答案:

答案 0 :(得分:15)

这里似乎至少有两个不同的问题。

首先,你不正确地使用Popen。以下是我看到的问题:

  1. 使用一个Popen生成多个进程。
  2. 将一个字符串作为args传递而不是分割args。
  3. 使用shell将文本传递给进程而不是内置的通信方法。
  4. 使用shell而不是直接生成进程。
  5. 以下是您的代码的更正版本

    from subprocess import PIPE
    
    args = ['nc', '-w', '1', 'server.com', 'port_num']
    p = subprocess.Popen(args, stdin=PIPE, stdout=PIPE)
    output = p.communicate("get file.ext")
    print output[0]
    

    其次,您建议在手动运行时比在子进程中运行时更快的结果表明此处的问题是您没有将正确的字符串传递给nc。可能发生的是服务器正在等待终止字符串以结束连接。如果你没有通过这个,那么连接可能会一直打开,直到它超时。

    手动运行nc,找出终止字符串是什么,然后更新传递给communicate的字符串。通过这些更改,它应该运行得更快。

答案 1 :(得分:12)

我希望subprocesscommand慢。没有意义暗示这是您的脚本运行缓慢的唯一原因,您应该查看commands源代码。少于100行,大部分工作委托给os的函数,其中许多函数直接来自c posix库(至少在posix系统中)。请注意commands仅限unix,因此无需进行任何额外工作即可确保跨平台兼容性。

现在看一下subprocess。有超过1500行,都是纯Python,进行各种检查以确保一致的跨平台行为。基于此,我希望subprocess的运行速度低于commands

我对这两个模块进行了计时,而对于一些非常基本的模块,subprocess的速度几乎是commands的两倍。

>>> %timeit commands.getoutput('echo "foo" | cat')
100 loops, best of 3: 3.02 ms per loop
>>> %timeit subprocess.check_output('echo "foo" | cat', shell=True)
100 loops, best of 3: 5.76 ms per loop

Swiss建议一些有助于您的脚本性能的良好改进。但即使应用它们,请注意subprocess 仍然更慢。

>>> %timeit commands.getoutput('echo "foo" | cat')
100 loops, best of 3: 2.97 ms per loop
>>> %timeit Popen('cat', stdin=PIPE, stdout=PIPE).communicate('foo')[0]
100 loops, best of 3: 4.15 ms per loop

假设您连续多次执行上述命令,这将累加起来,并至少考虑一些性能差异。

无论如何,我将您的问题解释为关于subprocesscommand的相对表现,而不是关于如何加速您的脚本。对于后一个问题,瑞士的答案更好。