2014-11-04 22 views
2

我有一個有趣的多處理問題,我可能可以利用它的結構。這個問題涉及Pandas中有大量列((df)),其功能func(〜80 * 79/2對)的df上運行,並且花費相當短的時間每次運行。多處理執行許多快速計算

的代碼看起來像

mgr = Manager() 
ns = mgr.Namespace() 
ns.df = df 

pool = Pool(processes=16) 
args = [(ns, list(combo)) for combo in list(combinations(df.columns, 2))] 
results = pool.map(func, args) 
pool.close() 

以上並不快,但比沒有游泳池,但速度更快只用了7個左右的一個因素。我擔心這麼多電話的開銷是問題所在。有沒有一種很好的方法來利用MultiProcessing的結構?

+0

pool.join()在此腳本中沒有做任何事情pool.map已經按照參數的順序返回一個列表,並且pool.close()已經關閉了您嘗試加入的池。 – Michael 2014-11-04 23:57:04

+0

哎呀謝謝邁克爾 – rhaskett 2014-11-05 00:36:06

回答

0

這是一個相當標準的結果。由於設置每個進程和在進程之間傳遞數據所需的開銷,並行運行時沒有任何東西可以完美地線性伸縮。請記住,(80 * 79)/2 = 3,160實際上是一個非常小的數字,假設該函數的計算量不是很大(即需要很長時間)。在其他條件相同的情況下,函數越快,使用多處理的開銷成本就越高,因爲設置附加進程的時間相對固定。

如果您必須對大型數據集進行多次重複(如果函數設計不當,則對每個進程重複一次),因爲進程不共享內存,所以多處理開銷主要集中在內存中。假設您的功能設置爲可以很容易地進行並行處理,只要您不超過計算機上的處理器數量,就可以添加更多的進程。大多數家用計算機沒有16個處理器(最多8個是典型的),而您的結果(並行速度快7倍)與您擁有的處理器少於16個一致。您可以用multiprocessing.cpu_count()檢查機器上的處理器數量。

編輯:

如果通過將列字符串,然後它會反覆使數據幀的副本並行化功能。例如:

def StringPass(string1, string2): 
    return df[string1] * df[string2] 

如果將StringPass並行化,它將在每個進程中至少複製一次數據幀。相反:

def ColumnPass(column1, column2): 
    return column1 * column2 

如果只傳遞必要的列ColumnPass只會在並行運行時將每次調用所需的列複製到函數中。因此,雖然StringPass(string1, string2)ColumnPass(df[string1], df[string2])將返回相同的結果,但在多處理時,前者會使全局df的幾個效率低下的副本,而後者將僅複製每次調用該函數所需的列。

+0

所以CPU的數量實際上是16。電腦相當健壯。這就是爲什麼當結果出來時我很擔心的原因。我希望Manager能夠避免DataFrame的重複,因爲它全部是隻讀的。我只是傳遞列的字符串名稱,所以應該沒有重複。 – rhaskett 2014-11-05 00:39:22

+0

你可以發佈該功能嗎?你說你只傳遞一個帶有列名的字符串,但函數如何從數據框中讀取?我的猜測是你只需引用函數中的數據框。如果您在主進程中運行它,則不會創建副本,但是在多進程中,每個進程都有自己的內存,並且無法訪問其他進程(包括主進程)的內存。因此,即使您沒有明確地將數據框傳遞給函數,它至少也會生成16個副本(每個進程一個)。 – Michael 2014-11-11 21:08:10

+0

而不是引用列,我會重寫函數來傳遞問題的實際列(或任何數據實際上是必要的功能工作)。這樣你只需複製你需要複製的任何給定進程/調用函數。 – Michael 2014-11-11 21:13:28