如何在没有主动等待(轮询)的情况下在Windows上等待Python中的多个子进程?像几乎这样的东西对我有用:
proc1 = subprocess.Popen(['python','mytest.py'])
proc2 = subprocess.Popen(['python','mytest.py'])
proc1.wait()
print "1 finished"
proc2.wait()
print "2 finished"
问题是当proc2
在proc1
之前完成时,父进程仍会等待proc1
。在Unix上,可以在循环中使用waitpid(0)
来获取子进程的返回代码 - 如何在Windows上用Python实现类似的东西?
答案 0 :(得分: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
答案 1 :(得分:5)
Twisted的asynchronous process-spawning API适用于Windows。实际上有几种不同的实现,其中许多并不是很好,但您可以在不改变代码的情况下在它们之间切换。
答案 2 :(得分: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!"
答案 3 :(得分:4)
Windows上的Twisted将执行主动等待。如果您不想使用线程,则必须使用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)
答案 4 :(得分: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)
答案 5 :(得分:0)
您可以使用psutil
import psutil
with psutil.Popen(["python", "mytest.py"]) as proc1, psutil.Popen(
["python", "mytest.py"]
) as proc2:
gone, alive = psutil.wait_procs([proc1, proc2], timeout=3)
'gone'和'alive'是指示哪些进程已消失而哪些进程仍在运行的列表。
您可以选择指定一个回调,该回调在每次被监视进程之一终止时调用:
def on_terminate(proc):
print "%s terminated" % proc
gone, alive = psutil.wait_procs(ls, timeout=3, callback=on_terminate)