我用python脚本做了很多计算。由于它受CPU约束,我使用线程模块的常用方法并没有产生任何性能改进。
我现在正在尝试使用多处理而不是多线程来更好地使用我的CPU并加快冗长的计算。
我在stackoverflow上找到了一些示例代码,但是我没有让脚本接受多个参数。有人可以帮我解决这个问题吗?我之前从未使用过这些模块,我很确定我使用的是Pool.map错误。 - 任何帮助表示赞赏。其他方法也可以实现多处理。
from multiprocessing import Pool
def calculation(foo, bar, foobar, baz):
# Do a lot of calculations based on the variables
# Later the result is written to a file.
result = foo * bar * foobar * baz
print(result)
if __name__ == '__main__':
for foo in range(3):
for bar in range(5):
for baz in range(4):
for foobar in range(10):
Pool.map(calculation, foo, bar, foobar, baz)
Pool.close()
Pool.join()
答案 0 :(得分:3)
正如您所怀疑的那样,您使用map
错误的方式多于一种方式。
map
的要点是在迭代的所有元素上调用一个函数。就像内置map
函数一样,但是并行。如果您想要排队一次,只需使用apply_async
。
针对您特别询问的问题:map
采用单参数函数。如果要传递多个参数,可以修改或包装函数以获取单个元组而不是多个参数(我将在最后显示),或者只使用starmap
。或者,如果你想使用apply_async
,它需要多个参数的函数,但你传递apply_async
一个参数元组,而不是单独的参数。
map
个实例上调用Pool
,而不是Pool
类。您尝试执行的操作类似于从文件类型尝试read
而不是从特定的打开文件中读取。Pool
。在你完成所有这些操作之前,你不想这样做,或者你的代码只是等待第一个完成,然后为第二个提出例外。因此,最小的改变是:
if __name__ == '__main__':
pool = Pool()
for foo in range(3):
for bar in range(5):
for baz in range(4):
for foobar in range(10):
pool.apply_async(calculation, (foo, bar, foobar, baz))
pool.close()
pool.join()
请注意,我将所有内容保留在if __name__ == '__main__':
块中 - 包括新的Pool()
构造函数。我不会在后面的示例中显示这一点,但是对于所有这些都是必要的,原因在文档的Programming guidelines部分中有所解释。 1
如果您想要使用其中一个map
函数,则需要一个可迭代的参数,如下所示:
pool = Pool()
args = ((foo, bar, foobar, baz)
for foo in range(3)
for bar in range(5)
for baz in range(4)
for foobar in range(10))
pool.starmap(calculation, args)
pool.close()
pool.join()
或者更简单:
pool = Pool()
pool.starmap(calculate, itertools.product(range(3), range(5), range(4), range(10)))
pool.close()
pool.join()
假设您没有使用旧版本的Python,可以使用Pool
语句中的with
进一步简化它:
with Pool() as pool:
pool.starmap(calculate,
itertools.product(range(3), range(5), range(4), range(10)))
使用map
或starmap
的一个问题是,它确实可以确保按顺序恢复结果。但是你只是回归None
并忽略它,为什么这样做呢?
使用apply_async
没有问题。
您也可以将map
替换为imap_unordered
,但没有istarmap_unordered
,因此您需要将您的函数包装为不需要starmap
:< / p>
def starcalculate(args):
return calculate(*args)
with Pool() as pool:
pool.imap_unordered(starcalculate,
itertools.product(range(3), range(5), range(4), range(10)))
<子> 1。如果您正在使用spawn
或forkserver
启动方法 - 而spawn
是Windows上的默认设置 - 每个子进程都会相当于import
您的模块。因此,所有不受__main__
后卫保护的顶级代码都会在每个孩子中运行。该模块试图保护您免受这种最严重的后果(例如,代替用计算机爆炸的孩子创建新的孩子,你会经常得到例外),但它不能使代码实际上工作。
答案 1 :(得分:-1)
尝试将calculation
作为calculation(foo, bar, foobar, baz)