Frage

Wie für mehr untergeordneten Prozesse in Python auf Windows, ohne aktiven wait (Polling) warten? So etwas wie diese fast funktioniert für mich:

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

Das Problem ist, dass, wenn proc2 vor proc1 abgeschlossen ist, wird nach wie vor dem übergeordneten Prozess für proc1 warten. Auf Unix würde man waitpid(0) in einer Schleife verwenden, um die untergeordneten Prozesse Rückgabecodes zu erhalten, wie sie fertig ist - wie so etwas in Python auf Windows erreichen

War es hilfreich?

Lösung

Es mag übertrieben, aber hier geht es:

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

Andere Tipps

Verdreht hat eine asynchronen Prozess-API Laichen , die funktioniert unter Windows. Es gibt tatsächlich mehrere unterschiedliche Implementierungen, von denen viele sind nicht so groß, aber man kann zwischen ihnen wechseln, ohne den Code zu ändern.

Aufbauend auf zseil Antwort, können Sie mit einer Mischung aus subprocess und win32-API-Aufrufen dies zu tun. Ich habe gerade ctypes, weil mein Python nicht haben, geschieht win32api installiert. Ich Laichen nur sleep.exe von MSYS hier als Beispiel, aber deutlich konnte man jeden Prozess erzeugen Sie möchten. Ich verwende Open () einen Griff aus dem Prozess PID zu bekommen, und dann WaitForMultipleObjects zu warten, für jeden Prozess zu beenden.

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!"

Verdrehte unter Windows wird eine aktive Wartezeit unter der Decke durchzuführen. Wenn Sie keine Threads verwenden wollen, müssen Sie die Win32-API verwenden, um Abfrage zu vermeiden. So etwas wie folgt aus:

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)

Sie können mit 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)

‚weg‘ und ‚lebendig‘ sind Listen angibt, welche Prozesse gegangen sind und welche sind noch am Leben.

Optional können Sie einen Rückruf angeben, die jedes Mal, wenn einer der überwachten Prozesse aufgerufen wird beendet:

>>> def on_terminate(proc):
...     print "%s terminated" % proc
...
>>> gone, alive = psutil.wait_procs(ls, timeout=3, callback=on_terminate)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top