似乎 python 会首先生成参数列表,然后将列表提供给函数“f”,即使使用 xrange。那是对的吗?
是的,因为您使用的是列表推导,它明确要求它生成该列表。
(请注意,这xrange
在这里并不重要,因为您一次只有两个范围,每个 10K 长;与参数列表的 100M 相比,这没什么。)
如果您希望它根据需要动态生成值,而不是一次生成全部 100M,您希望使用生成器表达式而不是列表推导。这几乎总是只是将括号变成括号的问题:
x=pool.map(f,((i,j) for i in range(10000) for j in range(10000)))
但是,正如您从源代码中看到的那样,如果您给它一个生成器,map
最终只会列出一个列表,所以在这种情况下,这不会解决任何问题。(文档没有明确说明这一点,但是如果它没有长度,很难看出它如何选择一个好的块大小来将可迭代对象切碎……)。
而且,即使这不是真的,您仍然会在结果中再次遇到同样的问题,因为pool.map
返回一个列表。
要解决这两个问题,您可以pool.imap
改用。它惰性地消耗可迭代对象,并返回结果的惰性迭代器。
需要注意的一件事是,imap
如果您不通过,则不会猜测最佳块大小,而只是默认为1
,因此您可能需要一些思考或反复试验来优化它。
此外,imap
当它们进来时,仍然会排队一些结果,因此它可以按照与参数相同的顺序将它们反馈给您。在病态的情况下,它最终可能会排队 (poolsize-1)/poolsize 的结果,尽管在实践中这种情况非常罕见。如果要解决此问题,请使用imap_unordered
. 如果您需要知道顺序,只需将索引与参数和结果一起来回传递:
args = ((i, j) for i in range(10000) for j in range(10000))
def indexed_f(index, (i, j)):
return index, f(i, j)
results = pool.imap_unordered(indexed_f, enumerate(args))
但是,我注意到在您的原始代码中,您根本没有对f(i, j)
. 在那种情况下,为什么还要费心收集结果呢?在这种情况下,您可以返回循环:
for i in range(10000):
for j in range(10000):
map.apply_async(f, (i,j))
但是,imap_unordered
可能仍然值得使用,因为它提供了一种非常简单的阻塞方法,直到所有任务完成,同时仍然让池本身运行以供以后使用:
def consume(iterator):
deque(iterator, max_len=0)
x=pool.imap_unordered(f,((i,j) for i in range(10000) for j in range(10000)))
consume(x)