2011-07-23 38 views
16

Tôi có một Trình quản lý (chuỗi chính), để tạo các Chủ đề khác để xử lý các thao tác khác nhau. Tôi muốn Quản lý của mình được thông báo khi một Chủ đề được tạo kết thúc (khi thực thi phương thức run() kết thúc).Cách truyền và chạy phương thức gọi lại bằng Python

Tôi biết tôi có thể làm điều đó bằng cách kiểm tra trạng thái của tất cả các chủ đề của tôi bằng phương thức Thread.isActive(), nhưng bỏ phiếu hút, vì vậy tôi muốn có thông báo.

Tôi đã nghĩ đến việc đưa ra một phương pháp gọi lại cho Chủ đề, và gọi chức năng này ở phần cuối của method 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? 
    ... 

Cảm ơn!

+1

Tôi quan tâm đến ví dụ về phương thức gọi lại không có ren. – ThorSummoner

Trả lời

15

Chủ đề không thể gọi cho người quản lý trừ khi nó có tham chiếu đến người quản lý. Cách dễ nhất để điều đó xảy ra là để người quản lý đưa nó vào luồng lúc khởi tạo.

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() 

Nếu bạn muốn để có thể gán một hàm hay phương pháp tùy tiện như một gọi lại, chứ không phải lưu trữ một tham chiếu đến đối tượng quản lý, điều này sẽ trở thành một chút vấn đề vì wrappers phương pháp và như vậy. Thật khó để thiết kế cuộc gọi lại để nó tham chiếu đến cả người quản lý chuỗi, đó là những gì bạn sẽ muốn. Tôi đã làm việc trên đó một thời gian và không nghĩ ra bất cứ điều gì tôi muốn xem xét hữu ích hay thanh lịch.

+1

Không phải dòng cuối cùng là 'thread.start()'? Nếu không, không có đa luồng thực sự nào sẽ xảy ra và 'MyThread.run()' được thực hiện giống như bất kỳ hàm nào khác. Nhưng nếu bạn thực sự chạy 'MyThread.start()' và tạo một luồng mới, 'self.parent.on_thread_finished (self, 42)' sẽ vẫn được thực thi trong bối cảnh của luồng mới thay vì chủ đề chính. Bạn sẽ cần một số loại đồng bộ hóa, như một [Queue] (http://docs.python.org/library/queue.html), vì vậy @ jonathan-lillesæter thực sự là chính xác. – iliis

+0

Mới đối với Python. Đây không phải là lạm dụng thừa kế sao? 'MyThread' không giống như một con logic của' Manager'. –

+0

'MyThread' không phải là con của' Manager'. – kindall

3

Nếu bạn muốn chủ đề chính đợi cho các chủ đề con hoàn thành việc thực hiện, có thể bạn nên sử dụng một số loại cơ chế đồng bộ hóa. Nếu chỉ đơn giản là được thông báo khi một hoặc nhiều chủ đề đã hoàn tất thi công, một Condition là đủ:

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() 

Tuy nhiên, sử dụng một Queue có lẽ là tốt hơn, vì nó làm cho xử lý nhiều công nhân luồng A chút dễ dàng hơn.

9

Có gì sai khi thực hiện theo cách này?

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

Bạn không thể chuyển phương thức cục bộ on_thread_finished vào luồng làm gọi lại vì phương thức cục bộ nhận hai đối số. Khi gọi lại được gọi từ chủ đề, nó sẽ chỉ đưa ra một đối số (dữ liệu) – Bharathwaaj

+8

Tôi biết điều này là muộn, nhưng đối với bất kỳ ai khác dành một giờ để viết lại một đoạn mã lớn: nhận xét của Bharathwaaj là * hoàn toàn không chính xác * và câu trả lời này hoạt động hoàn hảo. – Shariq

+0

@Shariq, sự cố là 'on_thread_finished' vẫn chạy trong chuỗi con, không phải trong' Trình quản lý'. Bạn không thể làm cho 'Manager' làm điều đó bởi vì' Manager' là * làm cái gì khác * vào lúc này. Để xem vấn đề, chỉ cần thực hiện 'Test()' trong một vòng lặp chết sau khi gọi 'MyThread()'. Ngoài ra, hãy xác định biến cục bộ và thử sử dụng biến đó trong 'on_thread_finished()', ví dụ: 'number_of_threads_running - = 1' – bytebuster

Các vấn đề liên quan