我目前处于这样一种情况:我有重复调用的并行化代码,并尝试减少与多处理相关的开销。因此,请考虑以下示例,该示例故意不包含"昂贵的"计算:
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实例。)
答案 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
尝试一下,你会发现现在它运行得更快。
调用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()
我找不到可能需要在不同对象中使用不同池的原因