web-dev-qa-db-ja.com

Pythonでコールバックメソッドを渡して実行する方法

さまざまな操作を処理する他のスレッドを作成するマネージャー(メインスレッド)があります。作成したスレッドが終了したときに(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?
    ...

ありがとう!

26
nbarraille

マネージャーへの参照がない限り、スレッドはマネージャーを呼び出すことができません。これを行う最も簡単な方法は、インスタンス化時にマネージャーがスレッドにそれを渡すことです。

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

マネージャーオブジェクトへの参照を格納するのではなく、コールバックとして任意の関数またはメソッドを割り当てられるようにしたい場合、メソッドラッパーなどが原因でこれは少し問題になります。コールバックを設計するのは難しいので、両方のマネージャーへの参照を取得しますおよびスレッド、これは必要なものです。私はしばらくそれについて作業しましたが、便利だとかエレガントだと思うものは思いつきませんでした。

21
kindall

この方法でそれを行うことで何か問題がありますか?

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"
9
combatdave

メインスレッドで子スレッドの実行が完了するのを待機する場合は、何らかの同期メカニズムを使用した方がよいでしょう。 1つ以上のスレッドの実行が終了したときに単に通知される場合は、 条件 で十分です。

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 を使用すると、複数のワーカースレッドの処理が少し簡単になるため、おそらくより優れています。