4

我試圖測量一段代碼,我使用Python的多處理程序包「並行化」,特別是使用Process函數。引入多處理隊列時執行時間增加

我有,我想並行運行兩個功能:function1function2function1不返回值,function2。函數2的返回值是一個相當大的類實例。

這裏是我現有的使用隊列並行並獲得返回值碼:

import multiprocessing as mpc 
... 
def Wrapper(self,...): 
    jobs = [] 
    q = mpc.Queue() 
    p1 = mpc.Process(target=self.function1,args=(timestep,)) 
    jobs.append(p1) 

    p2 = mpc.Process(target=self.function2,args=(timestep,arg1,arg2,arg3,...,q)) 
    jobs.append(p2) 

    for j in jobs: 
    j.start() 
    result = q.get() 

    for j in jobs: 
    j.join() 

所以,這裏是我看到的問題。如果我刪除了對result = q.get()的調用,執行Wrapper函數所需的時間顯着減少,因爲它不是從function2返回類,但是我顯然沒有從函數中獲取我需要的數據。如果我把它放回來,運行時間會大大增加,從而表明並行化實際上比順序執行這兩個函數花費的時間更長。

下面是一些意味着包裝的執行時間,以供參考:

  • 順序碼(即,function1(timestep)res = function2(timestep,a1,a2,a3,...,None)):10秒

  • 並行化的代碼,而無需使用一個隊列:8秒

  • 帶隊列的並行碼:60秒

此代碼的目標是展示如何並行化一段代碼可以提高執行不必要的並行函數所需的時間。作爲參考,我使用cProfile包,生成我的代碼配置文件,並查看Wrapper運行所需的時間。

我開始對整個過程感到沮喪。它的目的是基本上加速我已經添加到內部開發的現有自定義框架中的部分程序,但是我無法實際表明我沒有增加太多開銷。

如果我看節目的總執行時間,並行化的代碼運行得更快。但是,當我深入挖掘時,我的並行代碼開始顯得需要更長的時間。

現在,我的想法是,隊列正在做某種深層複製操作,但是我找不到引用來說明這一事實,所以我假設它正在返回一個淺拷貝,對我而言,不應該要求這樣的開銷。

回答

3

當您將對象傳遞到multiprocessing.Queue時,它需要在put一側進行酸洗,然後酸洗的字節必須刷新到管道。在get一側,需要從管道中讀取pickled字節,然後需要將它們取消放回到Python對象中。所以在現實中,multiprocessing.Queue的做法甚至比深度複製還要慢。

你看到的開銷幾乎可以肯定是要unpickle一個大對象所需的開銷的結果。這是一個並行編程領域,在這個領域中,Python真的很掙扎 - 如果你正在進行CPU綁定操作(因此不能使用線程來獲得並行性)並且需要共享狀態,那麼你會付出性能損失。如果你分享大型物品,懲罰可能會很大。 Python中的並行性是通過並行化某些CPU綁定操作獲得的性能提升和在進程之間共享狀態所獲得的性能之間的折中。因此,您的目標需要儘量減少共享狀態的數量,並最大限度地提高並行化的工作量。

一旦你這樣做了,不幸的是,你進一步減少性能的選擇是有限的。您可以嘗試將您的課程轉換爲​​對象,該對象允許您使用multiprocessing.sharedctypes在共享內存中創建對象。這應該比通過Queue返回對象更快,但是您必須處理​​的所有限制。

另一個想法是在multiprocessing.Manager服務器中創建對象。如果你這樣做,你的實際對象將存在於一個服務器進程中,並且父進程和子進程都將通過Proxy來訪問該對象。但是,這會使對象的每次讀取/寫入都變得更慢,因此最終可能不會比現在執行的Queue執行得更好。

這些替代方法都不是很好,它們可能都不適用於你的用例,在這種情況下,Python可能不是解決這個特定問題的最佳語言。別誤會我的意思;我喜歡Python並隨時使用它,但這是一個真正掙扎的領域。

+0

雖然有些令人沮喪聽到(因爲這是我害怕的東西),這是一個很好的答案。正如我試圖展示一個比較,你認爲爲並行和非並行代碼創建Manager服務器是值得的嗎?我認爲如果兩者都使用相同類型的共享對象,那麼在計算我的應用程序時,性能下降可能不太明顯。 – espais 2015-02-18 14:56:34

+0

@espais,好吧,如果你只是爲了演示的目的而這樣做,那麼你可以爲並行和順序代碼使用'Manager'。但是如果你想對「這裏是如何平行化代碼影響其性能」做一個準確的比較,現實情況是順序代碼不需要'Manager',而並行代碼則需要。如果你只是試圖展示並行化的力量,而這段代碼是一個隨心所欲的選擇,理想情況下你會有一個需要較少共享狀態的例子,所以並行化實際上更快......(續) ) – dano 2015-02-18 16:48:48

+0

@espais因爲現在你實際上發現,由於Python的限制,並行化這些特定的代碼實際上會傷害性能。理想情況下,你會發現你的代碼庫真的會從並行獲益,但你可能沒有任何合適的東西。 – dano 2015-02-18 16:50:02