为什么Python Multiprocessing Worker不会死?

时间:2015-07-27 19:00:38

标签: python python-multiprocessing pypy

我正在使用python多处理功能来映射某些元素的某些功能。有点像这样:

def computeStuff(arguments, globalData, concurrent=True):
    pool = multiprocessing.Pool(initializer=initWorker, initargs=(globalData,))
    results = pool.map(workerFunction, list(enumerate(arguments)))
    return results

def initWorker(globalData):
    workerFunction.globalData = globalData

def workerFunction((index, argument)):
    ... # computation here

通常我使用cPython和Pypy在ipython中运行测试。我注意到产生的过程通常不会被杀死,所以它们开始积累,每个都使用一个ram。在计算过程中按ctrl-k会发生这种情况,这会将多处理发送到混乱的大狂热中。但即使让计算完成,这些过程也不会在Pypy中消失。

根据文档,当池被垃圾收集时,它应该调用terminate()并终止所有进程。这里发生了什么事?我是否必须明确呼叫close()?如果是,是否有某种上下文管理器可以正确管理关闭资源(即进程)?

这是在Mac OS X Yosemite上。

1 个答案:

答案 0 :(得分:3)

PyPy的垃圾收集是懒惰的,因此无法调用 getSession().createQuery("from DynamicScenario").list(); 意味着close被“清除”,但这可能并不意味着“很快就会”。

Pool正确Pool d后,工作人员在任务用尽时退出。在3.3之前的Python中确保close关闭的简单方法是:

Pool

注意:我还删除了显式转换为from contextlib import closing def computeStuff(arguments, globalData, concurrent=True): with closing(multiprocessing.Pool(initializer=initWorker, initargs=(globalData,))) as pool: return pool.map(workerFunction, enumerate(arguments)) (无意义,因为list将为您迭代map迭代器),并直接返回结果(无需分配给一个名字只能在下一行返回。)

如果你想确保在异常情况下(在3.3之前的Python上)立即终止,你可以使用try / finally块,或者编写一个简单的上下文管理器(可以在你使用的其他地方重用它) enumerate):

Pool

from contextlib import contextmanager @contextmanager def terminating(obj): try: yield obj finally: obj.terminate() def computeStuff(arguments, globalData, concurrent=True): with terminating(multiprocessing.Pool(initializer=initWorker, initargs=(globalData,))) as pool: return pool.map(workerFunction, enumerate(arguments)) 方法的优势在于它可以保证流程立即退出;从理论上讲,如果你在主程序的其他地方使用线程,那么terminating工作者可能会使用非守护程序线程进行分叉,这样即使工作任务线程退出也会使进程保持活动状态; Pool通过强行杀死进程隐藏了这一点。

如果您的解释器是Python 3.3或更高版本,则terminating方法内置于terminating,因此Pool语句不需要特殊的包装器,with直接工作。