我在使用pydispatch模块进行线程间通信时遇到了问题。我使用了这里提供的示例:https://sites.google.com/site/hardwaremonkey/blog/python-howtocommunicatebetweenthreadsusingpydispatch
我稍微修改了它,以便在日志中提供更详细的信息。特别是,我让它显示了实际的线程名称:
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()
以下是我发现的内容:
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
见:
[Thread-Bob] Alice has received message: message from Bob
" Alice已收到消息"已在Bob的主题中执行。虽然我希望它能在爱丽丝的线程中执行。根据我的理解,调度员收到来自Bob的信号并直接在同一个线程中调用处理程序。所以它实际上是从Bob的线程中调用Alice的代码,导致意想不到的细微差别。
问题#1。当Alice处理信号时,Bob的执行实际上被阻止了。 问题#2。在更大的应用程序中,Alice可能会在多个并行线程中意外执行其代码。 问题#3。一般来说封装不良。我们希望Alice和Bob可以在一个实例中以自己的线程运行,每个实例彼此独立,只交换消息。这不是这种情况,因为他们实际上互相称呼代码。有没有办法为pydispatcher解决这个问题?或者你能推荐另一个库来进行没有这些问题的线程之间的通信吗?
答案 0 :(得分:1)
使用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()
因此,当消息从Bob到Alice时,信号处理程序实际上不执行处理消息的工作,而只调度执行该作业的实际处理程序的执行。而实际的处理程序将在Alice的线程中调用。
在这种情况下:
所以我的目标就实现了。
你们认为这是一个很好的解决方案吗?很想听到对此的评论。