正如您所怀疑的那样,您使用 map 的方式不止一种。
map 的要点是在可迭代的所有元素上调用函数。就像内置的 map 函数一样,但是是并行的。如果您想排队单个呼叫,只需使用apply_async。
对于您特别询问的问题:map 采用单参数函数。如果您想传递多个参数,您可以修改或包装您的函数以采用单个元组而不是多个参数(我将在最后展示),或者只使用starmap。或者,如果你想使用apply_async,它需要一个包含多个参数的函数,但你将apply_async 传递给一个参数元组,而不是单独的参数。
- 您需要在
Pool 实例上调用map,而不是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,您可以通过在 with 语句中使用 Pool 来进一步简化它:
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:
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__ 保护的顶级代码都将在每个孩子中运行。该模块试图保护您免受由此带来的一些最糟糕的后果(例如,不是用指数爆炸的孩子创建新孩子来对您的计算机进行分叉轰炸,而是经常遇到异常),但它不能使代码真正工作.