Как передать и запустить метод обратного вызова в Python - PullRequest
24 голосов
/ 23 июля 2011

У меня есть менеджер (основной поток), который создает другие потоки для обработки различных операций. Я бы хотел, чтобы мой менеджер был уведомлен о завершении созданного им потока (когда выполнение метода run () завершено).

Я знаю, что мог бы сделать это, проверяя состояние всех моих потоков с помощью метода 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?
    ...

Спасибо!

Ответы [ 3 ]

20 голосов
/ 23 июля 2011

Поток не может вызвать менеджера, если у него нет ссылки на менеджера. Самый простой способ для этого состоит в том, чтобы менеджер передал его потоку при создании экземпляра.

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

Если вы хотите иметь возможность назначать произвольную функцию или метод в качестве обратного вызова, а не сохранять ссылку на объект менеджера, это становится немного проблематичным из-за упаковщиков методов и тому подобного. Трудно спроектировать обратный вызов, поэтому он получает ссылку как на менеджер , так и поток, что вам и нужно. Я работал над этим некоторое время и не придумал ничего, что я бы посчитал полезным или изящным.

9 голосов
/ 25 июля 2011

Что-то не так с этим?

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"
3 голосов
/ 23 июля 2011

Если вы хотите, чтобы основной поток ожидал завершения дочерних потоков, вам, вероятно, лучше использовать какой-то механизм синхронизации.Если просто получить уведомление о завершении выполнения одного или нескольких потоков, достаточно Условие :

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

Однако лучше использовать Очередь , так какделает обработку нескольких рабочих потоков немного проще.

...