9

Python 2.7.3では、以下の問題は発生しません。ただし、私のマシン (64 ビット Mac OSX 10.7.3) では Python 2.7.1 と Python 2.6 の両方で発生します。これは私が最終的に配布するコードなので、Python のバージョンに劇的に依存せずにこのタスクを完了する方法があるかどうか知りたいです。

複数のサブプロセスを並行して開き、それぞれに STDIN データを書き込む必要があります。通常、私はPopen.communicateメソッドを使用してこれを行います。ただし、communicate複数のプロセスを同時に開いている場合は常にデッドロックになります。

import subprocess

cmd = ["grep", "hello"]
processes = [subprocess.Popen(cmd, stdin=subprocess.PIPE,
                              stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                                for _ in range(2)]

for p in processes:
    print p.communicate("hello world\ngoodbye world\n")

プロセス数を に変更するfor _ in range(1)と、出力は期待どおりになります。

('hello world\n', '')

ただし、プロセスが 2 つある場合 ( for _ in range(2))、プロセスは無期限にブロックされます。stdin に手動で書き込むという代替手段を試しました。

for p in processes:
    p.stdin.write("hello world\ngoodbye world\n")

しかし、プロセスから読み取ろうとすると (p.stdout.read()たとえば、) デッドロックが発生します。

最初はこれに関連しているように見えますが、複数のスレッドが使用されているときに発生し、デッドロックが非常にまれにしか発生しないことを示しています (ここでは常に発生します)。これを 2.7.3 より前のバージョンの Python で動作させる方法はありますか?

4

1 に答える 1

9

私はこれのために少し掘らなければなりませんでした。(私はかつて同様の問題に遭遇したので、答えを知っていると思っていましたが、間違っていました。)

この問題 (および 2.7.3 のパッチ) は次のとおりです。

http://bugs.python.org/issue12786

問題は、パイプがサブプロセスによって継承されることです。答えは、Popen 呼び出しで「close_fds=True」を使用することです。

processes = [subprocess.Popen(cmd, stdin=subprocess.PIPE,
               stdout=subprocess.PIPE, stderr=subprocess.PIPE,close_fds=True)
                            for _ in range(2)]

それが再利用したい他のファイル記述子で問題を引き起こす場合(これが単純化された例である場合)、作成された逆の順序でサブプロセスと wait()/communicate() できることが判明し、仕事に。

つまり、代わりに:

for p in processes:
    print p.communicate("hello world\ngoodbye world\n")

使用する:

while processes:
    print processes.pop().communicate("hello world\ngoodbye world\n")

(または、既存のループの前に「processes.reverse()」を実行するだけだと思います。)

于 2013-01-31T01:32:18.770 に答える