2017-11-25 9 views
1

スレッド間の通信にpydispatchモジュールを使用すると問題が発生しました。私はここで提供されている例を使用しました:https://sites.google.com/site/hardwaremonkey/blog/python-howtocommunicatebetweenthreadsusingpydispatchスレッド間のpydispatchの使用

私は少し詳細な情報をログに提供するために少し修正しました。特に、私はそれは同様に、実際のスレッド名が表示され作られた:ここでは

from pydispatch import dispatcher 
import threading 
import time 
import logging 

log_formatter = logging.Formatter('%(asctime)s %(levelname)s [%(name)s] [%(threadName)s] %(message)s', '%H:%M:%S') 
logger = logging.getLogger() 
logger.setLevel(logging.DEBUG) 
log_handler = logging.StreamHandler() 
log_handler.setLevel(logging.DEBUG) 
log_handler.setFormatter(log_formatter) 
logger.addHandler(log_handler) 


ALICE_SIGNAL='alice_signal' 
ALICE_SENDER='alice_sender' 
BOB_SIGNAL='bob_signal' 
BOB_SENDER='bob_sender' 

class Alice(): 
    ''' alice procrastinates and replies to bob''' 
    def __init__(self): 
     logger.debug('Alice instantiated') 
     dispatcher.connect(self.alice_dispatcher_receive, signal=BOB_SIGNAL, sender=BOB_SENDER) 
     self.alice() 

    def alice_dispatcher_receive(self, message): 
     ''' handle dispatcher''' 
     logger.debug('Alice has received message: {}'.format(message)) 
     dispatcher.send(message='thank you from Alice', signal=ALICE_SIGNAL, sender=ALICE_SENDER) 

    def alice(self): 
     ''' loop and wait ''' 
     while True: 
      logger.debug('Alice is procrastinating') 
      time.sleep(1) 

class Bob(): 
    ''' bob contacts alice periodically ''' 
    def __init__(self): 
     logger.debug('Bob instantiated') 
     dispatcher.connect(self.bob_dispatcher_receive, signal=ALICE_SIGNAL, sender=ALICE_SENDER) 
     self.bob() 

    def bob_dispatcher_receive(self, message): 
     ''' handle dispatcher ''' 
     logger.debug('Bob has received message: {}'.format(message)) 

    def bob(self): 
     ''' loop and send messages using a dispatcher ''' 
     while True: 
      dispatcher.send(message='message from Bob', signal=BOB_SIGNAL, sender=BOB_SENDER) 
      time.sleep(3) 


if __name__ == '__main__': 
    logger.debug('Starting...') 
    alice_thread = threading.Thread(target=Alice, name='Thread-Alice') 
    alice_thread.start() 
    bob_thread = threading.Thread(target=Bob, name='Thread-Bob') 
    bob_thread.start() 

は、私が見つけたものです:アリスが受信した」

[Thread-Bob] Alice has received message: message from Bob 

08:10:43 DEBUG [root] [MainThread] Starting... 
08:10:43 DEBUG [root] [Thread-Alice] Alice instantiated 
08:10:43 DEBUG [root] [Thread-Alice] Alice is procrastinating 
08:10:43 DEBUG [root] [Thread-Bob] Bob instantiated 
08:10:43 DEBUG [root] [Thread-Bob] Alice has received message: message from Bob 
08:10:43 DEBUG [root] [Thread-Bob] Bob has received message: thank you from Alice 
08:10:44 DEBUG [root] [Thread-Alice] Alice is procrastinating 
08:10:45 DEBUG [root] [Thread-Alice] Alice is procrastinating 
08:10:46 DEBUG [root] [Thread-Bob] Alice has received message: message from Bob 
08:10:46 DEBUG [root] [Thread-Bob] Bob has received message: thank you from Alice 
08:10:46 DEBUG [root] [Thread-Alice] Alice is procrastinating 
08:10:47 DEBUG [root] [Thread-Alice] Alice is procrastinating 
08:10:48 DEBUG [root] [Thread-Alice] Alice is procrastinating 
08:10:49 DEBUG [root] [Thread-Bob] Alice has received message: message from Bob 
08:10:49 DEBUG [root] [Thread-Bob] Bob has received message: thank you from Alice 
08:10:49 DEBUG [root] [Thread-Alice] Alice is procrastinating 

はこれを参照してください。ボブのスレッドで「メッセージ」が実行されました。私はそれがAliceのスレッドで実行されることを期待していましたが。私が理解していることから、ディスパッチャはBobからの信号を受け取り、同じスレッドでハンドラを呼び出すようにまっすぐに進みます。だから、実際にBobのスレッドからAliceのコードを呼び出し、予期せぬニュアンスが発生します。

問題#1。信号がAliceによって処理されている間、ボブの実行は実際にブロックされます。

問題#2。より大きなアプリケーションでは、Aliceは予期せずに複数の並列スレッドでコードを実行することがあります。

問題#3。一般的にカプセル化が不十分です。アリスとボブは、メッセージを交換するだけで、互いに独立してそれぞれ1つのインスタンスで独自のスレッドで実行されることが期待されます。実際にお互いのコードを呼び出すので、ここではそうではありません。

これをpydispatcherに解決する方法はありますか?または、これらの問題のないスレッド間の通信用に別のライブラリを推奨することはできますか?

答えて

0

event_loop.call_soon_threadsafe()を使用して解決策が見つかりました。メッセージは、ボブからアリスに到着したときに、シグナルハンドラが実際にメッセージを処理するジョブを実行しません

def register_signal_handler(loop, handler, signal, sender): 
    def dispatcher_receive(message): 
     loop.call_soon_threadsafe(handler, message) 
    dispatcher.connect(dispatcher_receive, signal=signal, sender=sender, weak=False) 


class Alice(): 
    def __init__(self): 
     logger.debug('Alice instantiated') 
     self.loop = asyncio.new_event_loop() 
     asyncio.set_event_loop(self.loop) 
     register_signal_handler(self.loop, self.alice_receive, signal=BOB_SIGNAL, sender=BOB_SENDER) 
     self.alice() 

    def alice_receive(self, message): 
     logger.debug('Alice has received message: {}'.format(message)) 
     dispatcher.send(message='thank you from Alice', signal=ALICE_SIGNAL, sender=ALICE_SENDER) 

    def alice(self): 
     def procrastinate(): 
      logger.debug('Alice is procrastinating') 
      self.loop.call_later(1, procrastinate) 
     procrastinate() 
     self.loop.run_forever() 

class Bob(): 
    def __init__(self): 
     logger.debug('Bob instantiated') 
     self.loop = asyncio.new_event_loop() 
     asyncio.set_event_loop(self.loop) 
     register_signal_handler(self.loop, self.bob_receive, signal=ALICE_SIGNAL, sender=ALICE_SENDER) 
     self.bob() 

    def bob_receive(self, message): 
     logger.debug('Bob has received message: {}'.format(message)) 

    def bob(self): 
     def poke_alice(): 
      dispatcher.send(message='message from Bob', signal=BOB_SIGNAL, sender=BOB_SENDER) 
      self.loop.call_later(3, poke_alice) 
     self.loop.call_later(3, poke_alice) 
     self.loop.run_forever() 

が、その実際のハンドラのだけスケジュール実行:ここ

はコードは今ありますジョブを実行します。実際のハンドラはAliceのスレッドで呼び出されます。この場合

  1. 信号は常に最初に近く、瞬時に、決してブロック送信者のスレッドに処理されます。
  2. アリスのコードはアリスのスレッドで常に実行されます。ボブのコードは常にボブのスレッドで実行されます。

私の目標はここにあります。

これは良い解決策だと思いますか?これについてのコメントを聞いて欲しいです。

関連する問題