[英]Multiprocessing in python to speed up functions
我對Python多處理感到困惑。
我正在嘗試加速從數據庫處理字符串的函數,但我必須誤解多處理是如何工作的,因為函數在給予工作池時需要比“正常處理”更長的時間。
這是我想要實現的一個例子。
from time import clock, time
from multiprocessing import Pool, freeze_support
from random import choice
def foo(x):
TupWerteMany = []
for i in range(0,len(x)):
TupWerte = []
s = list(x[i][3])
NewValue = choice(s)+choice(s)+choice(s)+choice(s)
TupWerte.append(NewValue)
TupWerte = tuple(TupWerte)
TupWerteMany.append(TupWerte)
return TupWerteMany
if __name__ == '__main__':
start_time = time()
List = [(u'1', u'aa', u'Jacob', u'Emily'),
(u'2', u'bb', u'Ethan', u'Kayla')]
List1 = List*1000000
# METHOD 1 : NORMAL (takes 20 seconds)
x2 = foo(List1)
print x2[1:3]
# METHOD 2 : APPLY_ASYNC (takes 28 seconds)
# pool = Pool(4)
# Werte = pool.apply_async(foo, args=(List1,))
# x2 = Werte.get()
# print '--------'
# print x2[1:3]
# print '--------'
# METHOD 3: MAP (!! DOES NOT WORK !!)
# pool = Pool(4)
# Werte = pool.map(foo, args=(List1,))
# x2 = Werte.get()
# print '--------'
# print x2[1:3]
# print '--------'
print 'Time Elaspse: ', time() - start_time
我的問題:
所以你的第一個問題是在foo(x)
沒有發生實際的並行性,你將整個列表傳遞給函數一次。
1)進程池的想法是讓許多進程在某些數據的不同位上進行計算。
# METHOD 2 : APPLY_ASYNC
jobs = 4
size = len(List1)
pool = Pool(4)
results = []
# split the list into 4 equally sized chunks and submit those to the pool
heads = range(size/jobs, size, size/jobs) + [size]
tails = range(0,size,size/jobs)
for tail,head in zip(tails, heads):
werte = pool.apply_async(foo, args=(List1[tail:head],))
results.append(werte)
pool.close()
pool.join() # wait for the pool to be done
for result in results:
werte = result.get() # get the return value from the sub jobs
如果處理每個塊所需的時間大於啟動過程所需的時間,那么這只會給你一個實際的加速,如果你要完成四個過程和四個工作,當然這些動態會發生變化。我們有4個流程和100個工作要做。 請記住,您正在創建一個全新的python解釋器四次,這不是免費的。
2)你對map有的問題是它在一個單獨的進程中將foo
應用於List1
中的每個元素,這將花費很長時間。 因此,如果你的游泳池有4個進程map
將彈出列表中的項目四次並將其發送到要處理的進程 - 等待進程完成 - 彈出更多的列表內容 - 等待進程完成。 這僅在處理單個項目需要很長時間時才有意義,例如,如果每個項目都是指向一個千兆字節文本文件的文件名。 但是,當它站在map時,只需要獲取列表中的單個字符串並將其傳遞給foo
,其中apply_async
將獲取列表的一部分。 請嘗試以下代碼
def foo(thing):
print thing
map(foo, ['a','b','c','d'])
這是內置的python映射,將運行單個進程,但多進程版本的想法完全相同。
根據JFSebastian的評論添加:但是您可以使用chunksize
參數進行map
以指定每個塊的大致大小。
pool.map(foo, List1, chunksize=size/jobs)
我不知道在Windows上是否存在map
問題,因為我沒有可用於測試的地圖。
3)是的,因為你的問題足夠大,足以證明你可能需要新的python解釋器
4)無法給出明確的答案,因為它取決於核心/處理器的數量等,但一般情況下它應該在Windows上正常。
問題(2)在Dougal和Matti的指導下,我弄清楚出了什么問題。 原始foo函數處理列表列表,而map需要一個函數來處理單個元素。
新功能應該是
def foo2 (x):
TupWerte = []
s = list(x[3])
NewValue = choice(s)+choice(s)+choice(s)+choice(s)
TupWerte.append(NewValue)
TupWerte = tuple(TupWerte)
return TupWerte
jobs = 4
size = len(List1)
pool = Pool()
#Werte = pool.map(foo2, List1, chunksize=size/jobs)
Werte = pool.map(foo2, List1)
pool.close()
print Werte[1:3]
感謝所有幫助我理解這一點的人。
所有方法的結果:對於List * 2 Mio記錄:正常13.3秒,與異步並行:7.5秒,與具有chuncksize的地圖並行:7.3,沒有chunksize 5.2秒
如果您有興趣,這是一個通用的多處理模板。
import multiprocessing as mp
import time
def worker(x):
time.sleep(0.2)
print "x= %s, x squared = %s" % (x, x*x)
return x*x
def apply_async():
pool = mp.Pool()
for i in range(100):
pool.apply_async(worker, args = (i, ))
pool.close()
pool.join()
if __name__ == '__main__':
apply_async()
輸出看起來像這樣:
x= 0, x squared = 0
x= 1, x squared = 1
x= 2, x squared = 4
x= 3, x squared = 9
x= 4, x squared = 16
x= 6, x squared = 36
x= 5, x squared = 25
x= 7, x squared = 49
x= 8, x squared = 64
x= 10, x squared = 100
x= 11, x squared = 121
x= 9, x squared = 81
x= 12, x squared = 144
如您所見,數字不是有序的,因為它們是異步執行的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.