Uso di python 2.7.4 su Windows (Nota: WinXP - un commentatore qui sotto suggerisce che funziona correttamente su Win7), ho uno script che crea diversi thread ognuno dei quali esegue un processo figlio tramite Popen con lo stdout/stderr reindirizzato ai file e le chiamate wait(). Ogni Popen ha i suoi propri file stdout/stderr. Dopo ogni ritorni di processo, a volte ho per eliminare i file (in realtà li sposta altrove).Python Popen su Windows con multithreading - impossibile cancellare i log stdout/stderr
Sto trovando che non riesco a cancellare i log stdout/stderr fino a dopo che tutte le chiamate wait() ritornano. Prima di ciò ricevo "WindowsError: [Errore 32] Il processo non può accedere al file perché è utilizzato da un altro processo ". Sembra che Popen stia trattenendo in qualche modo i file stderr fino a quando c'è almeno un processo figlio aperto, anche se i file non sono condivisi.
Codice di prova da riprodurre di seguito.
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]
Se si esegue questo, vedrete che ogni retryDelete() gira su un errore di accesso al file fino a quando tutti i processi figli sono finiti.
UPDATE: il problema si verifica anche se i descrittori di file stdof e stdef non vengono passati al costruttore Popen. Tuttavia, ciò non avviene (cioè le eliminazioni avvengono immediatamente) se il Popen viene rimosso e l'attesa() sostituita con time.sleep (self.idx). Dal momento che il Popen sembra avere un effetto sui descrittori di file che non sono passati ad esso mi chiedo se questo problema è legato alla gestione dell'ereditarietà.
UPDATE: close_fds = True dà un errore (non supportato su Windows quando il reindirizzamento output/error), e l'eliminazione dell'oggetto Popen con del p dopo la chiamata wait() non fa alcuna differenza per il problema.
UPDATE: sysinternals utilizza explorer di processo per cercare i processi con le maniglie nel file. Ridotto il test a soli 2 thread/bambini e reso il secondo rimane aperto a lungo. La ricerca handle ha mostrato che l'unico processo con handle su stderr0.log era il processo padre python, con due handle aperti.
UPDATE: Per il mio attuale, l'uso urgente, ho trovato una soluzione, che è quello di creare uno script separato che prende la riga di comando e stderr/log stdout file come parametri e viene eseguito il processo figlio reindirizzato. Il genitore esegue quindi questo script di supporto con os.system(). I file di registro vengono quindi liberati correttamente e vengono eliminati. Tuttavia, sono comunque molto interessato alla risposta a questa domanda. Mi sembra un bug specifico per WinXP, ma è ancora possibile che stia facendo qualcosa di sbagliato.
Si suppone che si passi 'stdof' e' stdef' a 'Popen'? –
Sì, grazie, Janne. Tuttavia, questo non è correlato al problema, che persiste dopo la correzione. Ho aggiornato l'esempio. – Tom
Hmmm - interessante, però. Forse il problema non è legato a Popen. Probabilmente sto solo facendo qualcosa di stupido ... – Tom