2014-03-25 59 views
2

我正在工作在多線程環境中,並且看起來像這樣一類(含過量噪聲去除):classmethods線程安全嗎?

class B: 

    @classmethod 
    def apply(cls, item): 
     cls.do_thing(item) 

    @classmethod 
    def do_thing(cls, item) 
     'do something to item' 

    def run(self): 
     pool = multiprocessing.Pool() 
     for list_of_items in self.data_groups: 
      pool.map(list_of_items, self.apply) 

我擔心的是,兩個線程可能會調用applydo_thing在同一時間,或者子類可能會嘗試在這些函數之一中使用cls做一些愚蠢的事情。我可以使用staticmethod而不是classmethod,但調用do_thing會變得複雜得多,特別是如果一個子類重新實現其中一個而不是另一個。所以我的問題是這樣的:上面的類是線程安全的,還是存在使用類方法的潛在問題?

回答

3

方法是否線程安全取決於方法的作用。

僅使用局部變量是線程安全的。但是當你從不同線程改變同一個非本地變量時,它變得不安全。

‘do something to item’似乎只修改給定的對象,它獨立於列表中的任何其他對象,所以它應該是線程安全的。

如果同一個對象在列表中多次出現,您可能需要考慮使對象線程安全。這可以通過在修改對象的每個方法中使用with self.object_scope_lock:來完成。

無論如何,你在這裏做的是使用進程而不是線程。在這種情況下,對象被酸洗並通過管道發送到另一個進程,在那裏它們被修改併發回。與線程相反,進程不共享內存。所以我不認爲在類方法中使用鎖會產生影響。

http://docs.python.org/3/library/threading.html?highlight=threading#module-threading

3

在這方面,classmethods和常規函數(和實例方法)之間沒有區別。它們都不是自動線程安全的。

如果一個或多個類方法/方法/函數可以同時處理來自不同線程的數據結構,則需要添加同步保護,通常使用threading.Lock s。

+0

感謝您的回答。那麼就簡單地調用'cls.do_thing'危險沒有鎖?直覺上我不這麼認爲,但我沒有太多的多線程經驗。 – aquavitae

+0

依賴於'thing'' do_thing()'做... – shx2

0

兩個其他的答案都在的do_thing()的安全性依賴於函數內部發生了什麼技術上是正確的。

但更準確的答案是,呼叫本身是安全的。換句話說,如果apply()do_thing()pure functions,那麼你的代碼是安全的。任何不安全性都將歸因於它們不是純粹的功能(例如,在執行期間依靠或影響共享變量)

正如shx2所提到的,類方法在視覺上只是「在」類中,用於分組。他們對班級的任何實例都沒有固有的依戀。因此,該代碼是在功能大致相當於:

def apply(item): 
    do_thing(item) 

def do_thing(item) 
    'do something to item' 

class B: 
    def run(self): 
     pool = multiprocessing.Pool() 
     for list_of_items in self.data_groups: 
      pool.map(list_of_items, apply) 

進一步的說明上給出的併發其他答案:

  1. threading.Lock是很容易理解的,但應該是你最後的手段。在天真的實現中,它通常比完全線性處理更慢。如果您可以使用諸如threading.Eventqueue.Queuemultiprocessing.Pipe來代替傳輸信息,那麼您的代碼通常會更快。
  2. asyncio是python3中的新熱點。這樣做有點困難,但通常是最快的方法。
  3. 如果你想在Python中使用一個很棒的演練現代併發技術,請核心開發人員Raymond Hettinger's Keynote on Concurrency。整件事很好,但lock的缺點從t = 57:59開始突出顯示。