使用池

时间:2017-10-31 23:26:32

标签: python multiprocessing pool

我目前处于这样一种情况:我有重复调用的并行化代码,并尝试减少与多处理相关的开销。因此,请考虑以下示例,该示例故意不包含"昂贵的"计算:

import multiprocessing as mp
def f(x):
    # toy function
    return x*x

if __name__ == '__main__':
    for x in range(500):
        pool = mp.Pool(processes=2) 
        print(pool.map(f, range(x, x + 50)))
        pool.close()
        pool.join()  # necessary?

此代码需要53秒,而顺序方法需要0.04秒。

第一个问题:在这种情况下,当只使用pool.map()时,我真的需要调用pool.join()吗?我省略了它没有找到任何负面影响,运行时间会下降到4.8秒。 (我知道省略pool.close()是不可能的,因为我们会泄漏线程。)

现在,虽然这将是一个很好的改进,但作为第一个答案,我可能会得到"好吧,不要在第一个地方创建游泳池"。没问题,但是并行化代码实际上存在于实例方法中,所以我会使用:

class MyObject:
    def __init__(self):
        self.pool = mp.Pool(processes=2)
    def function(self, x):
        print(self.pool.map(f, range(x, x + 50)))

if __name__ == '__main__':
    my_object = MyObject()
    for x in range(500):
        my_object.function(x)

这将是我最喜欢的解决方案,因为它在0.4秒内运行。

第二个问题:我应该在某处显式调用pool.close()/ pool.join()(例如在MyObject的析构函数中)还是当前代码足够? (如果重要的话:可以假设在我的项目中只有几个长期存在的MyObject实例。)

2 个答案:

答案 0 :(得分:0)

当然需要很长时间:你会继续为每个x分配一个新池并销毁它。

如果您这样做,它的运行速度会快得多:

if __name__ == '__main__':
    pool = mp.Pool(processes=2) # allocate the pool only once
    for x in range(500):
        print(pool.map(f, range(x, x + 50)))

    pool.close() # close it only after all the requests are submitted 
    pool.join() # wait for the last worker to finish

尝试一下,你会发现现在它运行得更快。

以下是指向joinclose的文档的链接:

调用close后,您无法向池中提交更多任务,join会等到最后一个工作人员完成工作。应该按顺序调用它们(首先关闭然后加入)。

答案 1 :(得分:0)

嗯,实际上你可以将已经分配的池作为参数传递给你的对象:

class MyObject:
    def __init__(self, pool):
        self.pool = pool

    def function(self, x):
        print(self.pool.map(f, range(x, x + 50)))


if __name__ == '__main__':
    with mp.Pool(2) as pool:
        my_object = MyObject(pool)
        my_second_object = MyObject(pool)

        for x in range(500):
            my_object.function(x)
            my_second_object.function(x)

        pool.close()

我找不到可能需要在不同对象中使用不同池的原因