我有一个可以通过websocket端点获得的python服务器。 在提供连接期间,它还与一些后端服务进行通信。此通信是异步的,可能会触发websocket的send()方法。
当提供单个客户端时,它似乎工作正常。但是,当并行提供多个客户端时,一些处理连接的例程偶尔会被卡住。更确切地说,它似乎在recv()方法中阻塞。
实际代码有点复杂,问题比我描述的稍微复杂一点,尽管如此,我提供了一个最小的代码框架,它描绘了我使用webockets的方式:
class MinimalConversation(object):
def __init__(self, ws, worker_sck, messages, should_continue_conversation, should_continue_listen):
self.ws = ws
self.messages = messages
self.worker_sck = worker_sck
self.should_continue_conversation = should_continue_conversation
self.should_continue_listen = should_continue_listen
async def run_conversation(self):
serving_future = asyncio.ensure_future(self.serve_connection())
listening_future = asyncio.ensure_future(self.handle_worker())
await asyncio.wait([serving_future, listening_future], return_when=asyncio.ALL_COMPLETED)
async def serve_connection(self):
while self.should_continue_conversation():
await self.ws.recv()
logger.debug("Message received")
self.sleep_randomly(10, 5)
await self.worker_sck.send(b"Dummy")
async def handle_worker(self):
while self.should_continue_listen():
self.sleep_randomly(50, 40)
await self.worker_sck.recv()
await self.ws.send(self.messages.pop())
def sleep_randomly(self, mean, dev):
delta = random.randint(1, dev) / 1000
if random.random() < .5:
delta *= -1
time.sleep(mean / 1000 + delta)
显然,在实际代码中,我不会以随机间隔睡眠,也不会使用给定的消息列表,但这会勾勒出我处理websockets的方式。在实际设置中,可能会发生一些错误,这些错误也会通过websocket发送,因此理论上可能会发生并行发送()但我从未遇到过这种情况。
代码从一个处理函数运行,该函数作为参数传递给websockets.serve(),初始化MinimalConversation对象并调用run_conversation()方法。
我的问题是:
Thak you。
答案 0 :(得分:1)
recv
函数仅在收到消息时返回,并且似乎有2个连接等待来自彼此的消息,因此可能存在类似于&#34;死锁&#34;的情况。当他们在等待对方的消息时,无法发送任何内容。也许你应该尝试重新考虑整体算法,使其更加安全。
当然,尝试添加更多调试输出,看看到底发生了什么。
是send()方法的并发调用危险吗?
如果并发你的意思是在同一个线程中但是在独立调度的协同程序中,则并行发送就好了。但要注意&#34; parallel&#34; recv
在同一个连接上,因为协同调度的顺序可能远非显而易见,而是决定哪个recv
调用将首先获得消息。
您能否就使用websockets和asyncio提出一些好的做法?
根据我的经验,最简单的方法是为传入连接创建专用任务,该连接将在连接上重复调用recv
,直到连接关闭。您可以将连接存储在某处并在finally
块中删除它,然后可以从其他协同程序中使用它来发送内容。