2011-07-23 74 views
16

我有一個Manager(主線程),它創建其他線程來處理各種操作。 我希望我的管理器在它創建的線程結束時(當run()方法執行完成時)得到通知。如何在Python中傳遞和運行回調方法

我知道我可以通過使用Thread.isActive()方法檢查我的所有線程的狀態,但輪詢很糟糕,所以我想要通知。

我確實想給回調方法的線程,並在run()方法的最後調用這個函數:

class Manager(): 
    ... 
    MyThread(self.on_thread_finished).start() # How do I pass the callback 

    def on_thread_finished(self, data): 
     pass 
    ... 

class MyThread(Thread): 
    ... 
    def run(self): 
     .... 
     self.callback(data) # How do I call the callback? 
    ... 

謝謝!

+1

我對非線程回調方法示例感興趣。 – ThorSummoner

回答

15

線程無法調用管理器,除非它具有對管理器的引用。最簡單的方法是讓經理在實例化時將其交給線程。

class Manager(object): 
    def new_thread(self): 
     return MyThread(parent=self) 
    def on_thread_finished(self, thread, data): 
     print thread, data 

class MyThread(Thread): 

    def __init__(self, parent=None): 
     self.parent = parent 
     super(MyThread, self).__init__() 

    def run(self): 
     # ... 
     self.parent and self.parent.on_thread_finished(self, 42) 

mgr = Manager() 
thread = mgr.new_thread() 
thread.start() 

如果你希望能夠指定任意函數或方法的回調,而不是存儲在管理對象的引用,這成爲是因爲方法和包裝等的有點問題。設計回調很困難,因此它得到了對線程的管理器的引用,這是您所需要的。我花了一段時間,並沒有拿出任何我認爲有用或優雅的東西。

+1

最後一行不應該是'thread.start()'?否則,不會發生實際的多線程,並且像任何其他函數一樣執行MyThread.run()。但是如果你實際運行MyThread.start()並創建一個新線程,self.parent.on_thread_finished(self,42)'仍然會在新線程的上下文中執行,而不是主線程。您需要某種同步,如[隊列](http://docs.python.org/library/queue.html),所以@ jonathan-lillesæter實際上是正確的。 – iliis

+0

Python新手。這不是濫用繼承嗎? 'MyThread'看起來不像'Manager'的邏輯子。 –

+0

'MyThread'不是'Manager'的子項。 – kindall

3

如果您希望主線程等待子線程完成執行,您最好使用某種同步機制。如果在一個或多個線程執行完畢後簡單地被通知,一個Condition是不夠的:

import threading 

class MyThread(threading.Thread): 
    def __init__(self, condition): 
     threading.Thread.__init__(self) 
     self.condition = condition 

    def run(self): 
     print "%s done" % threading.current_thread() 
     with self.condition: 
      self.condition.notify() 


condition = threading.Condition() 
condition.acquire() 

thread = MyThread(condition) 
thread.start() 

condition.wait() 

但是,使用Queue可能是更好的,因爲它使處理多個工作線程更容易一點。

9

這樣做有什麼問題嗎?

from threading import Thread 

class Manager(): 
    def Test(self): 
     MyThread(self.on_thread_finished).start() 

    def on_thread_finished(self, data): 
     print "on_thread_finished:", data 

class MyThread(Thread): 
    def __init__(self, callback): 
     Thread.__init__(self) 
     self.callback = callback 

    def run(self): 
     data = "hello" 
     self.callback(data) 

m = Manager() 
m.Test() # prints "on_thread_finished: hello" 
+0

您不能將本地方法on_thread_finished作爲回調傳遞給線程,因爲本地方法有兩個參數。當從線程調用回調函數時,它只會給出一個參數(數據) – Bharathwaaj

+8

我知道這是遲到的,但對於任何其他將要花一個小時重寫大塊代碼的人:Bharathwaaj的評論*完全不正確*而這個答案完美的作品。 – Shariq

+0

@Shariq,問題是'on_thread_finished'仍然在子線程中運行,而不是在'Manager'中運行。你不能讓'經理人'這樣做,因爲'經理人'在這個時候*正在做其他事*。爲了看到這個問題,在調用MyThread()之後,讓'Test()'掛在死循環中。或者,定義一個局部變量,並嘗試在'on_thread_finished()'中使用它,例如'number_of_threads_running - = 1' – bytebuster

相關問題