Windows의 Python - 여러 하위 프로세스를 기다리는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/100624

  •  01-07-2019
  •  | 
  •  

문제

활성 대기(폴링) 없이 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에서 이와 같은 작업을 수행하는 방법은 무엇입니까?

도움이 되었습니까?

해결책

너무 지나친 것처럼 보일 수도 있지만, 다음과 같습니다.

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

다른 팁

트위스트에는 비동기 프로세스 생성 API Windows에서 작동합니다.실제로는 여러 가지 구현이 있으며 그 중 대부분은 그다지 훌륭하지는 않지만 코드를 변경하지 않고도 구현 간에 전환할 수 있습니다.

zseil의 답변을 바탕으로 하위 프로세스와 win32 API 호출을 혼합하여 이를 수행할 수 있습니다.내 Python에는 win32api가 설치되어 있지 않기 때문에 직접 ctype을 사용했습니다.여기서는 예를 들어 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!"

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)

당신이 사용할 수있는 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)

'gone'과 'alive'는 어떤 프로세스가 사라졌고 어떤 프로세스가 아직 살아 있는지를 나타내는 목록입니다.

선택적으로 감시된 프로세스 중 하나가 종료될 때마다 호출되는 콜백을 지정할 수 있습니다.

>>> def on_terminate(proc):
...     print "%s terminated" % proc
...
>>> gone, alive = psutil.wait_procs(ls, timeout=3, callback=on_terminate)
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top