17

所以我写了一个脚本,在命令行上使用 nc 访问一堆服务器,最初我使用 Python 的 commands 模块并调用 commands.getoutput() 并且脚本运行了大约 45 秒。由于不推荐使用命令,因此我想将所有内容更改为使用 subprocess 模块,但现在脚本需要 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]

在此先感谢您的帮助!

4

2 回答 2

19

我预计subprocess会比command. 无意暗示这是您的脚本运行缓慢的唯一原因,您应该查看commands源代码。不到 100 行,大部分工作都委托给 from 的函数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

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

无论如何,我将您的问题解释为关于 and 的相对性能subprocesscommand而不是关于如何加快脚本的速度。对于后一个问题,Swiss 的回答更好。

于 2012-06-04T22:17:26.257 回答
18

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

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

  1. 使用一个 Popen 生成多个进程。
  2. 将一个字符串作为 args 传递,而不是拆分 args。
  3. 使用 shell 将文本传递给进程而不是内置的通信方法。
  4. 使用 shell 而不是直接生成进程。

这是您的代码的更正版本

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. 通过这些更改,它应该运行得更快。

于 2012-06-04T22:42:37.110 回答