簡體   English   中英

python多處理:設置類屬性值

[英]python multiprocessing : setting class attribute value

我有一個名為Experiment的類,另一個名為Case。 一個實驗由許多個案組成。 見下面的類定義,

from multiprocessing import Process

class Experiment (object):
    def __init__(self, name):
        self.name = name
        self.cases = []
        self.cases.append(Case('a'))
        self.cases.append(Case('b'))
        self.cases.append(Case('c'))

    def sr_execute(self):
        for c in self.cases:  
            c.setVars(6)

class Case(object):
    def __init__(self, name):
        self.name = name
    def setVars(self, var):
        self.var = var

在我的實驗課中,我有一個名為sr_execute的函數。 此功能顯示所需的行為。 我有興趣解析所有案例並為每個案例設置一個屬性。 當我運行以下代碼時,

if __name__ == '__main__':
    #multiprocessing.freeze_support()
    e = Experiment('exp')
    e.sr_execute()
    for c in e.cases: print c.name, c.var

我明白了

a 6
b 6
c 6

這是期望的行為。

但是,我想使用多處理並行執行此操作。 為此,我向實驗類添加了一個mp_execute()函數,

    def mp_execute(self):
        processes = []
        for c in self.cases: 
            processes.append(Process(target= c.setVars, args = (6,)))
        [p.start() for p in processes]
        [p.join() for p in processes]

但是,這不起作用。 當我執行以下操作時

if __name__ == '__main__':
    #multiprocessing.freeze_support()
    e = Experiment('exp')
    e.mp_execute()
    for c in e.cases: print c.name, c.var

我收到一個錯誤,

AttributeError: 'Case' object has no attribute 'var'

顯然,我無法使用多處理設置類屬性。

發生了什么事情的線索,

你打電話的時候:

def mp_execute(self):
    processes = []
    for c in self.cases: 
        processes.append(Process(target= c.setVars, args = (6,)))
    [p.start() for p in processes]
    [p.join() for p in processes]

當您創建Process ,它將使用您的對象的副本 ,並且對此類對象的修改不會傳遞給主程序,因為不同的進程具有不同的地址空間。 如果您使用Thread s,它將起作用,因為在這種情況下不會創建副本。

另請注意,您的代碼可能在Windows中失敗,因為您將方法作為target傳遞,而Windows要求target可被選擇(並且實例方法可選)。 target應該是在模塊頂層定義的函數,以便在所有Oses上工作。

如果您想與主進程通信,您可以進行以下更改:

無論如何,您必須通過設置“通道”(如Queue )或設置共享狀態來“明確”處理通信。


樣式注意:以這種方式使用列表內涵:

[p.join() for p in processes]

這完全是錯的 你只是浪費空間創建列表None秒。 正確的方式相比,它也可能更慢:

for p in processes:
    p.join()

因為它必須將元素附加到列表中。

有人說,列表內涵是比稍快for循環,但是:

  • 性能差異很小,通常無關緊要
  • 當且僅當您考慮這種循環時,它們會更快:

     a = [] for element in something: a.append(element) 

    如果循環,像在這種情況下, 不會創建一個list ,然后for循環會更快。

順便說一句:有些人以相同的方式使用map來執行副作用。 這又是錯誤的,因為你不會因為和以前一樣的原因獲得很多速度而且它在python3中完全失敗,其中map返回一個迭代器,因此它根本不會執行函數,從而使代碼不那么便攜。

@ Bakuriu的回答提供了良好的造型和效率建議。 確實,每個進程都獲得主進程堆棧的副本 ,因此除非您使用某種形式的IPC(例如Queue,Pipe,Manager),否則分叉進程所做的更改不會反映在主進程的地址空間中。

但具體的AttributeError: 'Case' object has no attribute 'var' ,你得到了一個額外的理由,即您的案例對象還沒有錯誤var在您啟動過程中的時間屬性。 相反, var屬性是在setVars()方法中創建的。

你的分叉進程在調用setVars()確實創建了變量 (實際上甚至將它設置為6),但是,這種變化只在Case對象的副本中,即沒有反映在主進程的內存空間中(變量仍然不存在)。

要了解我的意思,請將Case類更改為:

class Case(object):
    def __init__(self, name):
        self.name = name
        self.var = 7  # Create var in the constructor.
    def setVars(self, var):
        self.var = var

通過在構造函數中添加var成員變量,您的主進程將可以訪問它。 當然,分叉進程中的更改仍然不會反映在主進程中,但至少您不會收到錯誤:

a 7
b 7
c 7

希望這能夠揭示正在發生的事情。 =)


解:

最少侵入(對原始代碼)要做的是使用共享內存中的ctypes對象:

from multiprocessing import Value
class Case(object):
    def __init__(self, name):
        self.name = name
        self.var = Value('i', 7)              # Use ctypes "int" from shared memory.
    def setVars(self, var):
        self.var.value = var                  # Set the variable's "value" attribute.

並更改您的main()以打印c.var.value:

for c in e.cases: print c.name, c.var.value   # Print the "value" attribute.

現在您有了所需的輸出:

a 6
b 6
c 6

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM