[英]how to parallelize big for loops in python
我剛接觸Python,我仍處於學習曲線的陡峭階段。 感謝您提前發表任何意見。
我有一個很大的for循環運行(在很多迭代的意義上很大),例如:
for i in range(10000)
for j in range(10000)
f((i,j))
我認為這是一個常見的問題,如何對它進行並行化,並且在谷歌搜索了幾個小時后,我使用“多處理”模塊到達了解決方案,如下所示:
pool=Pool()
x=pool.map(f,[(i,j) for i in range(10000) for j in range(10000)])
這在循環很小時有效。 但是,如果循環很大,它實際上很慢,或者如果循環太大,有時會發生內存錯誤。 似乎python首先生成參數列表,然后將列表提供給函數“f”,甚至使用xrange。 那是對的嗎?
因此,這種並行化對我不起作用,因為我不需要將所有參數存儲在列表中。 有一個更好的方法嗎? 我感謝任何建議或參考。 謝謝。
似乎python首先生成參數列表,然后將列表提供給函數“f”,甚至使用xrange。 那是對的嗎?
是的,因為您正在使用列表推導,它明確要求它生成該列表。
(注意xrange
在這里並不重要,因為你一次只有兩個范圍,每個10K長;與參數列表的100M相比,這沒什么。)
如果您希望它根據需要動態生成值,而不是一次生成100M,則需要使用生成器表達式而不是列表推導。 這幾乎總是將括號括起來的問題:
x=pool.map(f,((i,j) for i in range(10000) for j in range(10000)))
但是,正如你可以從源代碼中看到的那樣 ,如果你給它一個生成器, map
最終會只列出一個列表,所以在這種情況下,這不會解決任何問題。 (文檔沒有明確說明這一點,但很難看出它如何能夠選擇一個好的chunksize來切斷迭代,如果它沒有長度...)。
而且,即使這不是真的,你仍然會再次遇到與結果相同的問題,因為pool.map
返回一個列表。
要解決這兩個問題,可以使用pool.imap
。 它懶惰地使用迭代,並返回結果的惰性迭代器。
有一點需要注意的是,如果你沒有傳遞一個, imap
不會猜測最好的chunksize,但是默認為1
,所以你可能需要一些思考或試驗和錯誤來優化它。
此外, imap
在進入時仍會排隊一些結果,因此它可以按照與參數相同的順序將它們反饋給您。 在病理情況下,它可能最終排隊(poolize-1)/ poolize你的結果,雖然在實踐中這是非常罕見的。 如果要解決此問題,請使用imap_unordered
。 如果您需要知道排序,只需使用args和結果來回傳遞索引:
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)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.