tutorial español await asyncio async python windows asynchronous

español - python async await



Python en Windows: ¿cómo esperar a múltiples procesos secundarios? (5)

Basándose en la respuesta de zseil, puede hacer esto con una combinación de llamadas API de subproceso y win32. Usé ctypes rectos, porque mi Python no tiene instalado win32api. Solo estoy generando sleep.exe de MSYS aquí como un ejemplo, pero claramente podría generar cualquier proceso que desee. Uso OpenProcess () para obtener un MANGO del PID del proceso y luego WaitForMultipleObjects para esperar a que finalice cualquier proceso.

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

¿Cómo esperar múltiples procesos secundarios en Python en Windows, sin espera activa (sondeo)? Algo como esto casi funciona para mí:

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

El problema es que cuando proc2 finaliza antes de proc1 , el proceso principal seguirá esperando por proc1 . En Unix se usaría waitpid(0) en un bucle para obtener los códigos de retorno de los procesos secundarios a medida que finalizan. ¿Cómo lograr algo como esto en Python en Windows?


Puede parecer excesivo, pero, aquí 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


Puedes usar 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)

''desaparecido'' y ''vivo'' son listas que indican qué procesos se han ido y cuáles siguen vivos.

Opcionalmente, puede especificar una devolución de llamada que se invoca cada vez que finaliza uno de los procesos supervisados:

>>> def on_terminate(proc): ... print "%s terminated" % proc ... >>> gone, alive = psutil.wait_procs(ls, timeout=3, callback=on_terminate)


Twisted en Windows realizará una espera activa debajo de las cubiertas. Si no desea utilizar subprocesos, deberá usar la API de win32 para evitar el sondeo. Algo como esto:

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)


Twisted tiene una API de generación de procesos asíncrona que funciona en Windows. En realidad, hay varias implementaciones diferentes, muchas de las cuales no son tan buenas, pero puede cambiar entre ellas sin cambiar su código.