2013-03-27 152 views
1

我想知道是否有可能開始一個新的線程,並更新其參數時,這種說法得到主的程序的新值更新參數,所以這樣的事情:的Python:螺紋

i = 0 

def foo(i): 
    print i 
    time.sleep(5) 

thread.start_new_thread(foo,(i,)) 

while True: 
    i = i+1 

非常感謝您的幫助!

+0

你試過這個嗎?發生了什麼? – 2013-03-27 20:19:30

回答

1

參數只是一個值,就像其他任何東西一樣。傳遞值只是對同一個值進行新的引用,如果您改變該值,則每個引用都會看到它。

全局變量和函數參數具有相同名稱的事實在這裏並不相關,並且有點令人困惑,所以我要重命名其中的一個。另外,您的foo函數只能在print一次(甚至可能在您增加值之前),然後休眠5秒鐘,然後結束。你可能想要一個循環,否則,你不能確定事情是否正常工作。

所以,這裏有一個例子:

i = [] 

def foo(j): 
    while True: 
     print j 
     time.sleep(5) 

thread.start_new_thread(foo,(i,)) 

while True: 
    i.append(1) 

那麼,爲什麼沒有你的代碼的工作?那麼,i = i+1沒有突變值0,它將新值值分配給ifoo函數仍舊引用舊值0,該值保持不變。

由於整數是不變的,所以不能直接解決這個問題。但你可以間接地很容易解決:替換整數與某種包裝 mutable。

例如,您可以使用setget方法編寫IntegerHolder類;當你i.set(i.get() + 1),而另一個參考i.get(),它會看到新的價值。

或者您可以使用list作爲持有人。列表是可變的,並保存零個或多個元素。當您執行i[0] = i[0] + 1時,用一個新的整數值替換i[0],但i仍然是相同的列表值,這就是其他參考指向的內容。所以:

i = [0] 

def foo(j): 
    print j[0] 
    time.sleep(5) 

thread.start_new_thread(foo,(i,)) 

while True: 
    i[0] = i[0]+1 

這可能看起來有點亂,但它實際上是一個很常見的Python成語。


同時,foo在另一個線程中運行這一事實會產生另一個問題。

理論上,線程同時運行,並且它們之間沒有任何數據訪問的排序。您的主線程可以在覈心0上運行,並且在覈心0的緩存中處理i的副本,而foo線程在覈心1上運行,並在核心1的緩存中處理另一個i副本,並且存在你的代碼中沒有任何東西強制高速緩存同步。

實際上,您經常會忽略這一點,特別是在CPython中。但實際上,當你知道時,你必須學習Global Interpreter Lock是如何工作的,以及解釋器如何處理變量以及(在某些情況下)如何處理平臺的緩存一致性和C實現的內存模型等工作。所以,你不應該依賴它。正確的做法是使用某種同步機制來防止訪問i。作爲一個方面說明,你也應該幾乎從不使用thread而不是threading,所以我也要切換它。

i = [] 
lock = threading.Lock() 

def foo(j): 
    while True: 
     with lock: 
      print j[0] 
     time.sleep(5) 

t = threading.Thread(target=foo, args=(i,)) 
t.start() 

while True: 
    with lock: 
     i[0] = i[0]+1 

最後一件事:如果你創建一個線程,你需要join它以後,也不能清晰地退出。但是你的foo線程永不退出,所以如果你嘗試join它,你將永遠阻止。

對於這樣的簡單情況,有一個簡單的解決方案。致電t.start()之前,請撥打t.daemon = True。這意味着當你的主線程退出時,後臺線程會在某個任意點自動終止。如果是寫入文件或數據庫,那顯然是一件壞事。但就你而言,它沒有做任何持久或危險的事情。

對於更實際的情況,您通常需要創建某種方式來在兩個線程之間發送信號。通常你已經得到了線程等待的東西 - Queue,一個文件對象或它們的集合(通過select)等。如果不是,只需創建一個由鎖(或條件或其他適當的東西)保護的標誌變量)。

+0

非常感謝您對線程工作方式的非常清晰的解釋。它現在更有意義,而且效果很棒!實際上,我的意思是在foo函數中使用while循環。 – Tomas 2013-03-29 12:10:44

0

嘗試使用全局變量。

i = 0 

def foo(): 
    print i 
    time.sleep(5) 

thread.start_new_thread(foo,()) 

while True: 
    i = i+1 

你也可以傳遞一個哈希來存放你需要的變量。

args = {'i' : 0} 

def foo(args): 
    print args['i'] 
    time.sleep(5) 

thread.start_new_thread(foo,(args,)) 

while True: 
    args['i'] = arg['i'] + 1 

您可能還想使用線程鎖定。

import thread 

lock = thread.allocate_lock() 
args = {'i' : 0} 

def foo(args): 
    with lock: 
     print args['i'] 
    time.sleep(5) 

thread.start_new_thread(foo,(args,)) 

while True: 
    with lock: 
     args['i'] = arg['i'] + 1 

希望這對我有所幫助。

+0

建議他使用全局函數來避免處理Python變量如何工作可能不是一個好主意。 – abarnert 2013-03-27 20:32:47

+0

@abarnert我也不會在這個例子中使用全局。我把這個全球化的例子,因爲我不知道他的需求需要什麼。 – Drew 2013-03-27 20:53:25