بايثون على نظام التشغيل ويندوز - كيف تنتظر الطفل متعددة العمليات ؟

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

  •  01-07-2019
  •  | 
  •  

سؤال

كيف تنتظر الطفل متعددة العمليات في بيثون على ويندوز دون الانتظار النشط (الاقتراع)?شيء مثل هذا تقريبا يعمل بالنسبة لي:

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.على يونكس واحد استخدام waitpid(0) في حلقة للحصول على الطفل العمليات عودة رموز كما أنها النهاية - كيفية تحقيق شيء من هذا القبيل في بيثون على ويندوز ؟

هل كانت مفيدة؟

المحلول

قد يبدو مبالغة ، ولكن ، من هنا نبدأ:

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 الذي يعمل على نظام التشغيل ويندوز.هناك في الواقع عدة تطبيقات مختلفة ، وكثير منها ليست كبيرة جدا, ولكن يمكنك التبديل بينهما دون تغيير التعليمات البرمجية الخاصة بك.

بناء على zseil الجواب ، يمكنك أن تفعل هذا مع مزيج من subprocess و استدعاءات win32 API.اعتدت على التوالي ctypes, لأن الثعبان لا يحدث لديهم win32api المثبتة.أنا فقط التفريخ sleep.exe من MSYS هنا كمثال على ذلك ، ولكن من الواضح أنك يمكن أن تفرخ أي عملية تريد.يمكنني استخدام 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!"

الملتوية على ويندوز سوف تؤدي نشط الانتظار تحت الأغطية.إذا كنت لا تريد استخدام خيوط, سيكون لديك لاستخدام 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)

'ذهب' و 'على قيد الحياة' هي قوائم مشيرا إلى العمليات التي ولت تلك التي لا تزال على قيد الحياة.

اختياريا يمكنك تحديد الاستدعاء الذي يحصل الاحتجاج في كل مرة واحدة من شاهد عمليات إنهاء:

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