Domanda

Come attendere per più processi figli in Python su Windows, senza attesa attiva (polling)?Qualcosa di simile a questo quasi per me funziona:

proc1 = subprocess.Popen(['python','mytest.py'])
proc2 = subprocess.Popen(['python','mytest.py'])    
proc1.wait()
print "1 finished"
proc2.wait()
print "2 finished"

Il problema è che quando proc2 finiture di prima proc1, il processo padre sarà ancora da attendere per proc1.In Unix si usa waitpid(0) in un ciclo per ottenere il bambino dei processi codici di ritorno come finiscono - come ottenere qualcosa di simile a questo in Python su Windows?

È stato utile?

Soluzione

Potrebbe sembrare eccessivo, ma, qui va:

import Queue, thread, subprocess

results= Queue.Queue()
def process_waiter(popen, description, que):
    try: popen.wait()
    finally: que.put( (description, popen.returncode) )
process_count= 0

proc1= subprocess.Popen( ['python', 'mytest.py'] )
thread.start_new_thread(process_waiter,
    (proc1, "1 finished", results))
process_count+= 1

proc2= subprocess.Popen( ['python', 'mytest.py'] )
thread.start_new_thread(process_waiter,
    (proc2, "2 finished", results))
process_count+= 1

# etc

while process_count > 0:
    description, rc= results.get()
    print "job", description, "ended with rc =", rc
    process_count-= 1

Altri suggerimenti

Twisted è un processo asincrono-la deposizione delle uova delle API che funziona su Windows.In realtà ci sono diverse implementazioni, molti dei quali non sono così grandi, ma è possibile passare tra di loro, senza modificare il codice.

Edificio zseil la risposta, si può fare questo con un mix di sottoprocesso e chiamate di API win32.Ho usato direttamente ctypes, perché il mio Pitone non capita di avere win32api installato.Io sono solo la deposizione delle uova sleep.exe da MSYS qui come esempio, ma è chiaro che si potrebbe generare qualsiasi processo che ti piace.Io uso OpenProcess() per ottenere una MANIGLIA da il PID del processo, e quindi WaitForMultipleObjects aspettare per qualsiasi processo di finitura.

import ctypes, subprocess
from random import randint
SYNCHRONIZE=0x00100000
INFINITE = -1
numprocs = 5
handles = {}

for i in xrange(numprocs):
    sleeptime = randint(5,10)
    p = subprocess.Popen([r"c:\msys\1.0\bin\sleep.exe", str(sleeptime)], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
    h = ctypes.windll.kernel32.OpenProcess(SYNCHRONIZE, False, p.pid)
    handles[h] = p.pid
    print "Spawned Process %d" % p.pid

while len(handles) > 0:
    print "Waiting for %d children..." % len(handles)
    arrtype = ctypes.c_long * len(handles)
    handle_array = arrtype(*handles.keys())
    ret = ctypes.windll.kernel32.WaitForMultipleObjects(len(handle_array), handle_array, False, INFINITE)
    h = handle_array[ret]
    ctypes.windll.kernel32.CloseHandle(h)
    print "Process %d done" % handles[h]
    del handles[h]
print "All done!"

Attorcigliata su permetterà a Windows di eseguire un'attesa attiva sotto le coperte.Se non si desidera utilizzare i thread, si dovrà utilizzare l'API win32 per evitare di polling.Qualcosa di simile a questo:

import win32process
import win32event

# Note: CreateProcess() args are somewhat cryptic, look them up on MSDN
proc1, thread1, pid1, tid1 = win32process.CreateProcess(...)
proc2, thread2, pid2, tid2 = win32process.CreateProcess(...)
thread1.close()
thread2.close()

processes = {proc1: "proc1", proc2: "proc2"}

while processes:
    handles = processes.keys()
    # Note: WaitForMultipleObjects() supports at most 64 processes at a time
    index = win32event.WaitForMultipleObjects(handles, False, win32event.INFINITE)
    finished = handles[index]
    exitcode = win32process.GetExitCodeProcess(finished)
    procname = processes.pop(finished)
    finished.close()
    print "Subprocess %s finished with exit code %d" % (procname, exitcode)

È possibile utilizzare psutil:

>>> import subprocess
>>> import psutil
>>> 
>>> proc1 = subprocess.Popen(['python','mytest.py'])
>>> proc2 = subprocess.Popen(['python','mytest.py'])    
>>> ls = [psutil.Process(proc1.pid), psutil.Process(proc2.pid)]
>>>
>>> gone, alive = psutil.wait_procs(ls, timeout=3)

e 'passata' e 'vivo' è una lista che indica quali processi sono andati e quelli che sono ancora vivi.

Facoltativamente, è possibile specificare una funzione di callback che viene richiamato ogni volta che la guardava processi termina:

>>> def on_terminate(proc):
...     print "%s terminated" % proc
...
>>> gone, alive = psutil.wait_procs(ls, timeout=3, callback=on_terminate)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top