Windows上的Python - 如何等待多个子进程?

25 投票
6 回答
22805 浏览
提问于 2025-04-11 09:18

在Windows上,如何在Python中等待多个子进程,而不使用主动等待(轮询)?类似下面的代码差不多可以用:

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

问题是,当proc2proc1之前完成时,父进程仍然会等待proc1。在Unix系统中,可以使用waitpid(0)在一个循环中获取子进程的返回码,等它们完成。那么在Windows上,如何实现类似的功能呢?

6 个回答

5

Twisted有一个异步进程创建的接口,这个接口可以在Windows系统上使用。实际上,这里有好几种不同的实现方式,虽然其中很多实现得并不好,但你可以在它们之间切换,而不需要修改你的代码。

7

在zseil的回答基础上,你可以通过结合使用子进程和win32 API来实现这个功能。我这里直接用了ctypes,因为我的Python环境里没有安装win32api。我只是用MSYS中的sleep.exe作为示例,但实际上你可以启动任何你想要的进程。我使用OpenProcess()来根据进程的PID获取一个句柄,然后用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!"
19

这可能听起来有点多余,但我还是来分享一下:

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

撰写回答