Python websockets卡住了

时间:2017-08-17 16:21:08

标签: python websocket python-asyncio

我有一个可以通过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()方法。

我的问题是:

  • 这样使用websockets是否存在根本性的错误?
  • send()方法的并发调用是否危险?
  • 您能否就使用websockets和asyncio提出一些好的做法?

Thak you。

1 个答案:

答案 0 :(得分:1)

recv函数仅在收到消息时返回,并且似乎有2个连接等待来自彼此的消息,因此可能存在类似于&#34;死锁&#34;的情况。当他们在等待对方的消息时,无法发送任何内容。也许你应该尝试重新考虑整体算法,使其更加安全。

当然,尝试添加更多调试输出,看看到底发生了什么。

  

是send()方法的并发调用危险吗?

如果并发你的意思是在同一个线程中但是在独立调度的协同程序中,则并行发送就好了。但要注意&#34; parallel&#34; recv在同一个连接上,因为协同调度的顺序可能远非显而易见,而是决定哪个recv调用将首先获得消息。

  

您能否就使用websockets和asyncio提出一些好的做法?

根据我的经验,最简单的方法是为传入连接创建专用任务,该连接将在连接上重复调用recv,直到连接关闭。您可以将连接存储在某处并在finally块中删除它,然后可以从其他协同程序中使用它来发送内容。