Python многопроцессорность: убить процесс, если он занимает слишком много времени, чтобы вернуться - PullRequest
1 голос
/ 19 января 2020

Ниже приведен простой пример, который зависает, потому что дочерний процесс завершается, ничего не возвращая, а родитель продолжает ждать вечно. Есть ли способ тайм-аута процесса, если он занимает слишком много времени и позволяет остальным продолжаться? Я новичок в многопроцессорности в python и нахожу документацию не очень полезной.

import multiprocessing as mp
import time

def foo(x):
    if x == 3:
        sys.exit()
    #some heavy computation here
    return result

if __name__ == '__main__':  
    pool = mp.Pool(mp.cpu_count)
    results = pool.map(foo, [1, 2, 3])

1 Ответ

1 голос
/ 19 января 2020

У меня была такая же проблема, и вот как я ее решил. Возможно, есть и другие лучшие решения, однако это решает и другие проблемы. Например, если процесс требует много ресурсов, может случиться, что обычное завершение займет некоторое время, чтобы пройти к процессу (что также может занять некоторое время) - поэтому существует принудительное завершение (kill -9). Эта часть, вероятно, работает только для Linux, поэтому вам, возможно, придется адаптироваться, если, если вы используете другую ОС.

Это часть моего собственного кода, поэтому, вероятно, его нельзя копировать.

from multiprocessing import Process, Queue
import os 
import time 

timeout_s = 5000 # seconds after which you want to kill the process

queue = Queue()  # results can be written in here, if you have return objects

p = Process(target=INTENSIVE_FUNCTION, args=(ARGS_TO_INTENSIVE_FUNCTION, queue))
p.start()

start_time = time.time()
check_interval_s = 5  # regularly check what the process is doing

kill_process = False
finished_work = False

while not kill_process and not finished_work:
    time.sleep(check_interval_s)  
    now = time.time()
    runtime = now - start_time

    if not p.is_alive():
        print("finished work")
        finished_work = True

    if runtime > timeout_s and not finished_work:
        print("prepare killing process")
        kill_process = True

if kill_process:
    while p.is_alive():
        # forcefully kill the process, because often (during heavvy computations) a graceful termination
        # can be ignored by a process.
        print(f"send SIGKILL signal to process because exceeding {timeout_s} seconds.")
        os.system(f"kill -9 {p.pid}")

        if p.is_alive():
            time.sleep(check_interval_s)
else:
    try:
        p.join(60)  # wait 60 seconds to join the process
        RETURN_VALS = queue.get(timeout=60)
    except Exception:
        # This can happen if a process was killed for other reasons (such as out of memory)
        print("Joining the process and receiving results failed, results are set as invalid.")
...