如何在 Linux 上强制一个函数及其所有子进程超时?
例如,multiprocessed_func
怎么可能被迫在 10 秒后完成:
import time
def multiprocessed_func(seconds):
# Assume this a long running function which uses
# multiprocessing internally and returns None.
time.sleep(seconds)
try:
multiprocessed_func(600)
except:
print('took too long')
借
用 psutil 文档,我们可以检查当前进程并在给定时间后终止或终止所有子进程。
def terminate_children(grace_period):
procs = psutil.Process().children()
for p in procs:
p.terminate()
gone, still_alive = psutil.wait_procs(procs, timeout=grace_period)
for p in still_alive:
p.kill()
raise TimeoutError
try:
multiprocessed_func(long_run=600)
time.sleep(10) # then timeout
terminate_children(grace_period=2)
except TimeoutError:
print('timed out')
pass
完整示例:
import multiprocessing
import time
import psutil
def slow_worker(long_run):
print('started')
time.sleep(long_run)
print('finished')
def multiprocessed_func(long_run):
jobs = []
for i in range(5):
p = multiprocessing.Process(target=slow_worker, args=(long_run,))
jobs.append(p)
p.start()
print('starting', p.pid)
def on_terminate(proc):
print('terminating {}, exit code {}'.format(proc, proc.returncode))
def terminate_children(grace_period):
procs = psutil.Process().children()
for p in procs:
p.terminate()
gone, still_alive = psutil.wait_procs(procs, timeout=grace_period,
callback=on_terminate)
for p in still_alive:
p.kill()
raise TimeoutError
try:
multiprocessed_func(long_run=600)
time.sleep(10)
terminate_children(grace_period=2)
except TimeoutError:
print('timed out')
pass
如果终止当前进程中的所有子进程过多,因为当前进程中还有其他多处理方法需要保留,那么我们可以multiprocessed_func包装在另一个进程中。
def safe_run(timeout, grace_period):
try:
multiprocessed_func(long_run=600)
time.sleep(timeout)
terminate_children(grace_period)
except TimeoutError:
pass
timeout, grace_period = 10, 2
p = multiprocessing.Process(target=safe_run, args=(timeout, grace_period,))
p.start()
p.join()
p.terminate()
time.sleep(2)
if p.is_alive():
p.kill()