2008-09-19 18 views
21

如何在Windows上等待Python中的多个子进程,而无需主动等待(轮询)?像这样的事情几乎作品我:Windows上的Python - 如何等待多个子进程?

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

的问题是,当proc1之前proc2结束,父进程将仍然等待proc1。在Unix上,一个循环中会使用waitpid(0)来完成子进程的返回代码 - 如何在Windows上的Python中实现这样的功能?

+0

你可以描述waitpid函数(0)你在Unix上使用? – 2010-01-27 19:55:58

+2

http://docs.python.org/library/os.html#os.waitpid UNIX上的waitpid(0)对于任何可用的子状态等待(除非`WNOHANG在选项中)并返回`(processid ,状态)`元组。 – 2010-01-28 08:29:00

回答

13

这可能似乎矫枉过正,但是,这里有云:

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 
+0

那么,如果调用不支持并行性,那么必须在外部实现它:-)谢谢! – 2008-09-19 10:16:44

5

双绞线有asynchronous process-spawning API它在Windows上运行。实际上有几种不同的实现方式,其中很多不是很好,但可以在不更改代码的情况下在它们之间切换。

4

在Windows上扭曲将在封面下执行一个主动等待。如果你不想使用线程,你将不得不使用win32 API来避免轮询。这样的事情:

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) 
5

基于zseil的答案,你可以做到这一点与子进程和win32 API调用混合。我使用了直接的ctypes,因为我的Python没有安装win32api。我只是在这里以MSYS产生sleep.exe为例,但显然你可以产生你喜欢的任何进程。我使用OpenProcess()从进程的PID中获取HANDLE,然后WaitForMultipleObjects等待任何进程完成。

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

您可以使用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) 

“水涨船高”和“活着”是列表表明哪些进程都消失了,哪些还活着。

可选方案,您可以指定被调用每次观看过程中的一个终止的回调:

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