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

the*_*ick 11 python performance command subprocess

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

我之前的所作所为:

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

我现在有

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

在此先感谢您的帮助!

Swi*_*iss 15

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

首先,你是不正确地使用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]
Run Code Online (Sandbox Code Playgroud)

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

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

  • 有理由2吗?为什么字符串版本被认为效率低下? (2认同)

sen*_*rle 12

我希望subprocess比它慢command.没有意义表明这是脚本运行缓慢的唯一原因,您应该查看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
Run Code Online (Sandbox Code Playgroud)

瑞士人提出了一些有助于你的剧本表现的良好改进.但是,即使应用它们后,请注意,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
Run Code Online (Sandbox Code Playgroud)

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

在任何情况下,我解释你的问题作为有关的相对性能subprocesscommand,而不是关于如何加快你的脚本.对于后一个问题,瑞士的答案更好.

  • 我怀疑这实际上不是问题. (2认同)