2009-07-26 20 views
4

我正在用Python的Queue.Queue類實現一個相對簡單的線程池。我有一個生產者類,其中包含Queue實例以及一些便利方法,以及threading.Thread的子類。我基於一個整數爲我的池中的每個線程實例化該對象(「工作線程」,我認爲它們被調用)。我是否應該將線程本地存儲用於只存在於{class,method}中的變量?

每個工作線程將flag, data從隊列中取出,使用自己的數據庫連接對其進行處理,並將該行的GUID放置到列表中,以便生產者類知道作業何時完成。

雖然我知道,其他模塊實現我編碼的功能,我編碼這樣做的原因是爲了更好地瞭解Python如何線程的作品。這使我想到了我的問題。

如果我存儲在一個函數的命名空間或在類的__dict__對象什麼,會不會是線程安全的?

class Consumer(threading.Thread): 
    def __init__(self, producer, db_filename): 
     self.producer = producer 
     self.conn = sqlite3.connect(db_filename) # Is this var thread safe? 
    def run(self): 
     flag, data = self.producer.queue.get() 

     while flag != 'stop': 
      # Do stuff with data; Is `data` thread safe? 

我想這兩個將是線程安全的,這是我的理由:

  • 每次一個類實例化時,一個新的__dict__被創建。在我上面概述的場景下,我認爲任何其他對象都不會引用此對象。 (現在,或許情況會如果我用join()的功能變得更加複雜,但我不...)
  • 每當一個函數被調用,它會創建自己的名字空間,存在功能的壽命。我沒有做任何變量global,所以我不明白任何其他對象如何引用一個函數變量。

This post有點我的問題,但對我來說仍然有點抽象。

在此先感謝您爲我解決這個問題。

回答

5

你是對的;這是線程安全的。局部變量(稱爲「函數名稱空間」的變量)始終是線程安全的,因爲只有執行函數的線程纔可以訪問它們。只要實例不在線程中共享,實例屬性就是線程安全的。由於消費者類從Thread繼承,所以它的實例肯定不會在線程間共享。

這裏唯一的「風險」是數據對象的價值:理論上,生產者可能在將數據對象放入隊列後保留數據對象,(如果數據對象本身是可變的 - 確保你理解什麼是「可變的」意思)可以在消費者使用它時改變對象。如果生產者在將數據對象放入隊列後獨自離開數據對象,這是線程安全的。

1

我認爲你的整體正確與你的假設,並在你的情況下,你很可能是正確的。

但是,如果某件事是線程安全的或者說不是線程安全的話,那麼稍微難一點。

呼叫如self.conn = sqlite3.connect(db_filename)可能不會,因爲sqlite3的模塊可以共享一些州和調用功能可能有一些副作用。但是,我懷疑是這種情況,像我一樣,我會認爲它正在產生一個全新的變量。

這不僅僅是全局變量可能是一個問題,從外部範圍獲得可變變量也是一個問題。

所以在

flag, data = self.producer.queue.get() 

的數據可能會或可能不會是線程安全的,具體情況取決於數據最初產生的。但是,我認爲這個數據將包含獨立的(最好是不可變的)信息。所以如果是這種情況,那麼所有應該是線程安全的。

1

爲了使數據線程安全,使用copy.deepcopy()在將數據放入隊列之前創建數據的新副本。然後生產者可以在下一個循環中修改數據,而無需在使用者拷貝之前修改它。

相關問題