TL; DR::呼叫future.set_result
不会立即解决loop.run_until_complete
。相反,它会再阻塞5秒钟。
完整上下文: 在我的项目中,我使用autobahn和asyncio通过websocket服务器发送和接收消息。对于我的用例,我需要一个用于Websocket通信的第二个线程,因为我有任意阻塞代码将在主线程中运行。主线程还需要能够安排消息,以便通信线程与服务器来回发送。我当前的目标是使用通信线程传递所有消息,从而发送一条来自主线程的消息,并阻塞直到响应返回为止。
这是我的代码的片段:
import asyncio
import threading
from autobahn.asyncio.websocket import WebSocketClientFactory, WebSocketClientProtocol
CLIENT = None
class MyWebSocketClientProtocol(WebSocketClientProtocol):
# -------------- Boilerplate --------------
is_connected = False
msg_queue = []
msg_listeners = []
def onOpen(self):
self.is_connected = True
for msg in self.msg_queue[::]:
self.publish(msg)
def onClose(self, wasClean, code, reason):
is_connected = False
def onMessage(self, payload, isBinary):
for listener in self.msg_listeners:
listener(payload)
def publish(self, msg):
if not self.is_connected:
self.msg_queue.append(msg)
else:
self.sendMessage(msg.encode('utf-8'))
# /----------------------------------------
def send_and_wait(self):
future = asyncio.get_event_loop().create_future()
def listener(msg):
print('set result')
future.set_result(123)
self.msg_listeners.append(listener)
self.publish('hello')
return future
def worker(loop, ready):
asyncio.set_event_loop(loop)
factory = WebSocketClientFactory('ws://127.0.0.1:9000')
factory.protocol = MyWebSocketClientProtocol
transport, protocol = loop.run_until_complete(loop.create_connection(factory, '127.0.0.1', 9000))
global CLIENT
CLIENT = protocol
ready.set()
loop.run_forever()
if __name__ == '__main__':
# Set up communication thread to talk to the server
threaded_loop = asyncio.new_event_loop()
thread_is_ready = threading.Event()
thread = threading.Thread(target=worker, args=(threaded_loop, thread_is_ready))
thread.start()
thread_is_ready.wait()
# Send a message and wait for response
print('starting')
loop = asyncio.get_event_loop()
result = loop.run_until_complete(CLIENT.send_and_wait())
print('done') # this line gets called 5 seconds after it should
问题::WebSocketClientProtocol收到对其外发消息的响应,并在其未决的将来调用set_result
,但是loop.run_until_complete
阻塞了另外4.9秒,直到最终解决。< / p>
我知道run_until_complete
还在事件循环中处理其他未决事件。主线程是否可能以某种方式将一堆事件排队,一旦我开始循环就必须立即处理这些事件?另外,如果我将run_until_complete
移入通信线程或将create_connection
移入主线程,则事件循环不会阻止我。
最后,我尝试在不使用高速公路的情况下重现此问题,但是我无法造成额外的延迟。我很好奇这是否可能与高速公路的回叫时间有关(例如onMessage
)。