17

そこで、コマンド ラインで nc を使用して一連のサーバーにアクセスするスクリプトを作成しました。もともとは Python のコマンド モジュールを使用して commands.getoutput() を呼び出していましたが、スクリプトは約 45 秒で実行されました。コマンドは非推奨なので、subprocess モジュールを使用するようにすべてを変更したいのですが、スクリプトの実行に 2 分 45 秒かかります。これがなぜなのか誰にも分かりますか?

私が以前に持っていたもの:

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 行未満であり、ほとんどの作業は の関数に委譲されておりos、その多くは (少なくとも posix システムでは) c posix ライブラリから直接取得されています。これcommandsは unix 専用であるため、クロスプラットフォームの互換性を確保するために追加の作業を行う必要はありません。

を見てみましょうsubprocess。1500 以上の行があり、すべて純粋な Python であり、あらゆる種類のチェックを行って、一貫したクロスプラットフォームの動作を保証します。subprocessこれに基づいて、より遅く実行されると予想されますcommands

私は 2 つのモジュールの時間を計りましたが、非常に基本的なものでsubprocessは、ほぼ 2 倍の速度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

上記のコマンドを連続して何度も実行すると仮定すると、これが合計され、少なくともパフォーマンスの違いの一部が説明されます。

いずれにせよ、私はあなたの質問を、スクリプトを高速化する方法ではなく、subprocessとの相対的なパフォーマンスに関するものとして解釈しています。command後者の質問については、Swiss の回答の方が適切です。

于 2012-06-04T22:17:26.257 に答える
18

ここには、少なくとも 2 つの個別の問題があるようです。

まず、Popen を不適切に使用しています。ここに私が見る問題があります:

  1. 1 つの Popen で複数のプロセスを生成します。
  2. 引数を分割する代わりに、1 つの文字列を引数として渡します。
  3. シェルを使用して、組み込みの通信メソッドではなくプロセスにテキストを渡します。
  4. プロセスを直接生成するのではなく、シェルを使用します。

ここにあなたのコードの修正版があります

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 に答える