2008-09-19 27 views
21

Làm thế nào để chờ đợi cho nhiều tiến trình con trong Python trên Windows, mà không cần chờ đợi hoạt động (bỏ phiếu)? Một cái gì đó như thế này gần công trình cho tôi:Python trên Windows - làm cách nào để đợi nhiều quy trình con?

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

Vấn đề là khi proc2 kết thúc trước khi proc1, quá trình cha mẹ sẽ vẫn chờ proc1. Trên Unix, người ta có thể sử dụng waitpid(0) trong một vòng lặp để lấy mã trả về của các tiến trình con khi chúng kết thúc - làm thế nào để đạt được một cái gì đó như thế này trong Python trên Windows?

+0

bạn có thể mô tả waitpid (0) bạn muốn sử dụng trên Unix? –

+2

http://docs.python.org/library/os.html#os.waitpid 'waitpid (0)' trên unix waits (trừ khi 'WNOHANG' có trong tùy chọn) cho bất kỳ trạng thái con có sẵn nào và trả về' (processid , trạng thái) 'tuple. –

Trả lời

13

Nó có vẻ quá mức cần thiết, nhưng ở đây nó đi:

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

Vâng, nếu cuộc gọi không hỗ trợ song song thì người ta phải thực hiện nó bên ngoài :-) Cảm ơn! –

+2

Tôi nghĩ có một lỗi nhỏ trong tập lệnh mẫu, tôi không thấy bất kỳ tuyên bố nào về loại: process_count - = 1 Không phải là "vòng lặp vô hạn" cuối cùng? –

+0

@Ricardo Reyes: có, sao chép-dán chưa hoàn tất. Cảm ơn bạn. – tzot

5

Twisted có asynchronous process-spawning API mà hoạt động trên Windows. Thực tế có nhiều cách triển khai khác nhau, nhiều trong số đó không tuyệt vời như vậy, nhưng bạn có thể chuyển đổi giữa chúng mà không cần thay đổi mã của mình.

4

Xoắn trên Windows sẽ thực hiện hoạt động chờ dưới nắp. Nếu bạn không muốn sử dụng các chủ đề, bạn sẽ phải sử dụng API win32 để tránh bỏ phiếu. Một cái gì đó như thế này:

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

Bạn đang sai về giải pháp luồng thực hiện một hoạt động chờ đợi. Tôi không biết về Twisted. –

5

Xây dựng trên câu trả lời của zseil, bạn có thể thực hiện điều này với sự kết hợp của quá trình xử lý con và win32 API. Tôi sử dụng ctypes thẳng, bởi vì Python của tôi không xảy ra để cài đặt win32api. Tôi chỉ sinh ra sleep.exe từ MSYS ở đây làm ví dụ, nhưng rõ ràng bạn có thể sinh ra bất kỳ quá trình nào bạn thích. Tôi sử dụng OpenProcess() để có được một HANDLE từ quá trình 'PID, và sau đó WaitForMultipleObjects để chờ đợi cho bất kỳ quá trình để kết thúc.

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

Bạn có thể sử dụng 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) 

'ra đi' và 'sống' là danh sách cho thấy các quy trình đang biến mất và những người thân mà vẫn còn sống.

tùy ý bạn thể chỉ định một callback mà được gọi mỗi khi một trong những quá trình quan sát chấm dứt:

>>> def on_terminate(proc): 
...  print "%s terminated" % proc 
... 
>>> gone, alive = psutil.wait_procs(ls, timeout=3, callback=on_terminate) 
Các vấn đề liên quan