2016-05-16 64 views
1

下面是一個簡單塞奇納羅:更新相同的實例變量來自不同進程的

class Test: 
    def __init__(self): 
     self.foo = [] 

    def append(self, x): 
     self.foo.append(x) 

    def get(self): 
     return self.foo 

def process_append_queue(append_queue, bar): 
    while True: 
     x = append_queue.get() 
     if x is None: 
      break 
     bar.append(x) 
    print("worker done") 

def main(): 
    import multiprocessing as mp 
    bar = Test() 
    append_queue = mp.Queue(10) 
    append_queue_process = mp.Process(target=process_append_queue, args=(append_queue, bar)) 
    append_queue_process.start() 

    for i in range(100): 
     append_queue.put(i) 
    append_queue.put(None) 
    append_queue_process.join() 

    print str(bar.get()) 

if __name__=="__main__": 
    main() 

當你在main()函數結束調用bar.get()爲何仍返回一個空列表?我該如何做到這一點,以便子進程也適用於Test的同一個實例,而不是一個新實例?

所有答案讚賞!

回答

1

一般而言,進程具有不同的地址空間,因此一個進程中某個對象的突變對任何其他進程中的任何對象都沒有影響。進程間通信需要告訴一個進程有關另一個進程所做的更改。

這可以明確地完成(使用諸如multiprocessing.Queue之類的東西),或者如果您爲此目的使用由multiprocessing實現的設施,則隱式地完成。例如,在封面下進行了大量工作,以更改跨過程可見的multiprocessing.Queue

在具體的例子,最簡單的方法是更換您的__init__功能,像這樣:

def __init__(self): 
    import multiprocessing as mp 
    self.foo = mp.Manager().list() 

恰巧,一個mp.Manager實例支持list()方法創建流程識別列表對象(其實是一個代理對於一個列表對象,它將列表操作轉發給維護單一副本「真實」列表的列表操作,列表對象並不真正在進程間共享,因爲這是不可能的 - 但代理使它出現待分享)。

所以如果你做了這個改變,你的代碼將顯示你期望的結果 - 並且沒有更簡單的方法。

請注意,多處理的效果越好,所需的IPC(進程間通信)就越少,這與應用程序或編程語言無關。

2

通過酸洗它們並在管道上傳遞字符串來在進程之間複製對象。沒有辦法在進程之間爲純Python對象實現真正的「共享內存」。要準確實現這種同步,請參閱multiprocessing.Manager文檔(https://docs.python.org/2/library/multiprocessing.html#managers),其中提供了有關常見Python容器類型的同步版本的示例。這些是「代理」容器,其中代理上的操作將跨過進程邊界發送所有參數,進行酸洗,然後在父進程中執行。

相關問題