python multiprocessing.Pool kill *specific* long running or hung process
我需要执行许多并行数据库连接和查询的池。 我想使用multiprocessing.Pool或current.futures ProcessPoolExecutor。 Python 2.7.5
在某些情况下,查询请求花费的时间太长或永远无法完成(挂起/僵尸进程)。 我想终止已超时的multiprocessing.Pool或current.futures ProcessPoolExecutor中的特定进程。
这是一个如何杀死/重新生成整个进程池的示例,但是理想情况下,我将CPU的抖动最小化,因为我只想杀死一个特定的长时间运行的进程,该进程在超时秒后仍未返回数据。
由于某些原因,在返回并完成所有结果之后,以下代码似乎无法终止/加入进程Pool。 它可能与超时发生时终止工作进程有关,但是池被杀死时会创建新的工作进程,并且结果符合预期。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | from multiprocessing import Pool import time import numpy as np from threading import Timer import thread, time, sys def f(x): time.sleep(x) return x if __name__ == '__main__': pool = Pool(processes=4, maxtasksperchild=4) results = [(x, pool.apply_async(f, (x,))) for x in np.random.randint(10, size=10).tolist()] while results: try: x, result = results.pop(0) start = time.time() print result.get(timeout=5), '%d done in %f Seconds!' % (x, time.time()-start) except Exception as e: print str(e) print '%d Timeout Exception! in %f' % (x, time.time()-start) for p in pool._pool: if p.exitcode is None: p.terminate() pool.terminate() pool.join() |
我不完全理解你的问题。您说要停止一个特定的进程,但是在异常处理阶段,您要对所有作业调用终止。不知道为什么要这么做。另外,我很确定使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | from multiprocessing import Pool import time import numpy as np from threading import Timer import thread, time, sys def f(x): time.sleep(x) return x if __name__ == '__main__': pool = Pool(processes=4, maxtasksperchild=4) results = [(x, pool.apply_async(f, (x,))) for x in np.random.randint(10, size=10).tolist()] result = None start = time.time() while results: try: x, result = results.pop(0) print result.get(timeout=5), '%d done in %f Seconds!' % (x, time.time()-start) except Exception as e: print str(e) print '%d Timeout Exception! in %f' % (x, time.time()-start) for i in reversed(range(len(pool._pool))): p = pool._pool[i] if p.exitcode is None: p.terminate() del pool._pool[i] pool.terminate() pool.join() |
关键是您需要从池中删除项目。仅对它们调用终止是不够的。
我也遇到了这个问题。
原始代码和@stacksia编辑的版本存在相同的问题:
在这两种情况下,当仅其中一个进程达到超时时(即完成
在我的解决方案下面找到。它涉及到@luart建议的每个工作进程创建一个
如果有人有更好的解决方案(例如将PID保存在内存中),请共享它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | #!/usr/bin/env python from multiprocessing import Pool import time, os import subprocess def f(x): PID = os.getpid() print 'Started:', x, 'PID=', PID pidfile ="/tmp/PoolWorker_"+str(x)+".pid" if os.path.isfile(pidfile): print"%s already exists, exiting" % pidfile sys.exit() file(pidfile, 'w').write(str(PID)) # Do the work here time.sleep(x*x) # Delete the PID file os.remove(pidfile) return x*x if __name__ == '__main__': pool = Pool(processes=3, maxtasksperchild=4) results = [(x, pool.apply_async(f, (x,))) for x in [1,2,3,4,5,6]] pool.close() while results: print results try: x, result = results.pop(0) start = time.time() print result.get(timeout=3), '%d done in %f Seconds!' % (x, time.time()-start) except Exception as e: print str(e) print '%d Timeout Exception! in %f' % (x, time.time()-start) # We know which process gave us an exception: it is"x", so let's kill it! # First, let's get the PID of that process: pidfile = '/tmp/PoolWorker_'+str(x)+'.pid' PID = None if os.path.isfile(pidfile): PID = str(open(pidfile).read()) print x, 'pidfile=',pidfile, 'PID=', PID # Now, let's check if there is indeed such process runing: for p in pool._pool: print p, p.pid if str(p.pid)==PID: print 'Found it still running!', p, p.pid, p.is_alive(), p.exitcode # We can also double-check how long it's been running with system 'ps' command:" tt = str(subprocess.check_output('ps -p"'+str(p.pid)+'" o etimes=', shell=True)).strip() print 'Run time from OS (may be way off the real time..) = ', tt # Now, KILL the m*$@r: p.terminate() pool._pool.remove(p) pool._repopulate_pool() # Let's not forget to remove the pidfile os.remove(pidfile) break pool.terminate() pool.join() |
许多人建议使用鹅卵石。它看起来不错,但仅适用于Python3。如果有人能够为python 2.6导入卵石,那就太好了。
为了避免访问内部变量,您可以将执行任务中的
但是,在工人的这种外部终止之后,将重新创建它们,但是池变得不可联接,并且还需要在
在您的解决方案中,您将篡改池本身的内部变量。该池依赖于3个不同的线程才能正确运行,在不真正知道自己在做什么的情况下干预其内部变量并不安全。
没有一种干净的方法可以停止在标准Python Pools中超时的过程,但是有一些替代实现可以暴露这种功能。
您可以看一下以下库:
卵石
台球