Windowsでpython 2.7.4を使用しています(注:WinXP - 以下のコメント欄はWin7で正しく動作することを示唆しています)、私はいくつかの スレッドそれぞれがPopenを介して子プロセスを実行し、 stdout/stderrがファイルにリダイレクトされ、wait()が呼び出されます。各Popenには のstdout/stderrファイルがあります。各プロセスが復帰すると、ファイルを削除するのに実際には があります(実際には別の場所に移動します)。マルチスレッドのPython Popen - stdout/stderrログを削除できません
私は、すべての wait()呼び出しが返されるまでstdout/stderrログを削除できないことを発見しました。その前に私は "WindowsError:[エラー32] プロセスで使用されているため、 プロセスはファイルにアクセスできません"というメッセージが表示されます。 ファイルが共有されていなくても、Popenは何らかの理由でstderrファイル を保持していると思われます。
以下に再現するテストコードです。
C:\ test1.py
import subprocess
import threading
import os
def retryDelete(p, idx):
while True:
try:
os.unlink(p)
except Exception, e:
if "The process cannot access the file because it is being used by another process" not in e:
raise e
else:
print "Deleted logs", idx
return
class Test(threading.Thread):
def __init__(self, idx):
threading.Thread.__init__(self)
self.idx = idx
def run(self):
print "Creating %d" % self.idx
stdof = open("stdout%d.log" % self.idx, "w")
stdef = open("stderr%d.log" % self.idx, "w")
p = subprocess.Popen("c:\\Python27\\python.exe test2.py %d" % self.idx,
stdout=stdof, stderr = stdef)
print "Waiting %d" % self.idx
p.wait()
print "Starting deleting logs %d" % self.idx
stdof.close()
stdef.close()
retryDelete("stderr%d.log" % self.idx, self.idx)
print "Done %d" % self.idx
threads = [Test(i) for i in range(0, 10)]
for thread in threads:
thread.start()
for thread in threads:
thread.join()
C:\ test2.py:あなたはこれを実行する場合
import time
import sys
print "Sleeping",sys.argv[1]
time.sleep(int(sys.argv[1]))
print "Exiting",sys.argv[1]
は、あなたがそれぞれretryDelete()は、ファイルアクセスエラーにスピンしていることがわかりますすべての子プロセスが終了するまで
UPDATE:この問題は、stdofおよびstdefファイル記述子がPopenコンストラクタに渡されなくても発生します。しかし、Popenが削除され、wait()がtime.sleep(self.idx)に置き換えられた場合、それは起こりません(つまり、直ちに削除が行われます)。 Popenはそれに渡されないファイル記述子に影響を与えているように見えるので、この問題が継承を処理することに関連しているのだろうかと思います。
UPDATE:close_fds = Trueの場合(標準出力/標準エラー出力をリダイレクトしないときに、Windowsでサポートされています)エラーを与え、待機()呼び出しの後にデルのpでpopenのオブジェクトを削除する問題に違いはありません。
UPDATE:ファイルへのハンドルを持つプロセスを探すためにsysinternalsプロセスエクスプローラを使用しました。テストをわずか2スレッド/子供に減らし、2番目のテストを長時間開いたままにしました。ハンドル検索では、stderr0.logへのハンドルを持つ唯一のプロセスが、親Pythonプロセスであり、ハンドルが2つ開いていることがわかりました。
UPDATE:私の現在、緊急の使用のために、私はパラメータとしてコマンドラインとstderr/stdoutをログファイルを取り、リダイレクトされた子プロセスを実行する別のスクリプトを作成することです回避策を、見つけました。親はos.system()でこのヘルパースクリプトを実行するだけです。その後、ログファイルは正常に解放され、削除されます。しかし、私はまだこの質問の答えに興味があります。 WinXP固有のバグのような感じですが、まだ間違っています。
'' Popen'に 'stdof'と' stdef'を渡すはずですか? –
はい - ありがとう、Janne。しかし、それはこの問題とは無関係であり、修正後も維持されます。私は例を更新しました。 – Tom
Hmmm - 面白いですが。多分問題はPopenに関連していないでしょう。私はおそらくちょうど何かばかげている... – Tom