2012-12-04 48 views
3

我想在python中建立一個依賴於多個線程的程序,在線程之間共享數據。我試圖避免使用全局關鍵字來做這件事,但目前爲止沒有取得任何進展。如何在共享資源時避免python線程中的全局?

作爲一個簡單的例子(下面的代碼),我的main()函數生成一個線程thread1,它應該能夠訪問變量count,在這種情況下只是爲了打印它。與此同時,main()迭代這個變量,並且thread1應該能夠看到計數改變。一些自包含的代碼在這裏:

import threading 
import time 

class myThread (threading.Thread): 

    def __init__(self, threadID): 
     self.threadID = threadID 
     threading.Thread.__init__(self) 

    def run(self): 
     global count 
     for i in range(10): 
      print "count is now: ", count, " for thread ", self.threadID, "\n" 
      time.sleep(5) 


def main(): 

    global count 
    count = 0 

    # spawn one or more threads 
    thread1 = myThread(1) 
    thread1.start() 

    for i in range(20): 
     time.sleep(2) 
     count = count + 1 

    # wait for thread1 to finish 
    thread1.join() 

main() 

當閱讀有關蟒蛇線程,我還沒有發現任何其他方式來做到這一點比使用全球。然而,在閱讀全球時,大多數人認爲你應該很少使用它,因爲很好的理由,有些人甚至認爲它應該完全從Python中刪除。所以我想知道是否實際上有另一種方法讓thread1「被動地」檢測到main()已經迭代計數並訪問該新值?例如。我不太瞭解python和指針(它們甚至存在於python中嗎?),但我會認爲這正是全球達到的目標。

理想情況下,我可以從main()調用一個thread1方法來設置一個新的self.count,只要count被迭代,但是因爲thread1有一個阻塞的run()方法,我看不到如何做這在thread1內部沒有另外一個獨立的線程,這看起來太複雜了。

+1

使用'threading.Lock'來控制對全局的訪問。爲了避免全局派生一個'threading.Thread'計數器子類,它根據需要獲取和釋放它自己的私有Lock屬性,以防止兩個進程同時訪問內部計數器值。 – martineau

+0

實際上,沒有任何理由從你的問題的'threading.Thread'派生計數器子類。它所需要的只是能夠被一個以上的線程使用,這可以通過它的Lock成員變量來完成。 – martineau

+0

好點@martineau,只爲未來的讀者,我決定在這裏不使用鎖,主要是因爲我只是從main()更改變量,並且更改所討論的變量是一個原子操作,即thread1永遠不會讀取中途增量計數。 (雖然我不是專家,但如果我錯了,請糾正我的錯誤) – funklute

回答

2

您可以創建線程對象並填寫類屬性。

import threading 
class MyThreadClass(threading.Thread): 
    def __init__(self, fruits): 
    threading.Thread.__init__(self) 
    self.fruits = fruits  

    def run(self): 
    self.fruits.append('banana') 

list_fruit = ['apple', 'orange']  
print 'BEFORE:', list_fruit 
thread = MyThreadClass(list_fruit) 
thread.start() 
thread.join() #Wait for the thread to finish 
print 'AFTER:', list_fruit 

輸出:

BEFORE: ['apple', 'orange'] 
AFTER: ['apple', 'orange', 'banana'] 

對於你的情況,你可以嘗試:

import threading 
import time 

class myThread (threading.Thread): 

    def __init__(self, threadID): 
     self.threadID = threadID 
     self.count = 0 
     threading.Thread.__init__(self) 

    def run(self): 
     for i in range(10): 
      print "count is now: ", self.count, " for thread ", self.threadID, "\n" 
      time.sleep(5) 


def main():  
    # spawn one or more threads 
    thread1 = myThread(1) 
    thread1.start() 

    for i in range(20): 
     time.sleep(2) 
     thread1.count = thread1.count + 1 

    # wait for thread1 to finish 
    thread1.join() 
    print thread1.count 

main() 

如果你想使用多個線程之間共享相同的數,你可以把你的計數一個只包含一個元素的列表。 這樣,當爲線程屬性分配計數時,它不會是硬拷貝。

+0

雖然如果全局的話,它會被拋棄,但一般來說它不是一個好的模式,因爲它有兩個或多個線程訪問共享數據,而沒有某種鎖定機制。在簡單的例子中,它沒有什麼壞處,只是因爲這兩個線程都沒有對數據做任何重要的事情,但在現實的使用情況下,訪問不協調的事實可能是有害的。此外,最後關於將數量列入清單的部分是沒有意義的。 – martineau

+0

@Omar我想你的意思是「GIL」([Global Interpreter Lock](https://wiki.python。組織/莫恩/ GlobalInterpreterLock))。但是,無論如何你應該使用鎖,[見](http://stackoverflow.com/a/1718843/2291710)。 – Delgan

+0

如果有人想知道是否可以通過一個**隊列**與線程進行通信:給出__init __(self,queue)隊列,那麼你可以在'init'中'self.queue = queue',這樣你可以在run()方法中使用隊列。儘管被標記爲「自我」,但所有線程以及創建類實例的類的外部方法之後共享相同的隊列。 – user136036

相關問題