Skip to main content
 首页 » 编程设计

python之Django Channels websocket 通信不是真正的异步

2024年12月31日34Terrylee

我编写了 django channel 代码,通过 websockets 从两个不同的源异步发送 api 数据。不同的来源需要几秒到 1 分钟来计算和发回数据。我设法使用 asyncio 事件循环异步调用它们。但问题是他们没有异步发回响应。该代码只是等待所有数据到达并同时发送所有数据。

channel 代码:

class SearchHotelConsumer(AsyncWebsocketConsumer): 
    def __init__(self, *args, **kwargs): 
        super().__init__(*args, **kwargs) 
        self.source1 = Source1() 
        self.source2 = Source2() 
 
    async def connect(self): 
        await self.accept() 
 
    def disconnect(self, close_code): 
        pass 
 
    async def _source1_handler(self, request, queue): 
        source1_response = await self.source1.async_post(request) 
 
        await queue.put(source1_response.data) 
 
    async def _source2_handler(self, request, queue): 
        source2_response = await self.source2.async_post(request) 
 
        await queue.put(source2_response.data) 
 
    async def _send_msg(self, queue): 
        while True: 
            message = await queue.get() 
            if message is None: 
                break 
            print('got the message') 
            await self.send(text_data=json.dumps({ 
                'message': message 
            }, cls=DjangoJSONEncoder)) 
 
            queue.task_done() 
 
    def receive(self, text_data): 
        text_data_json = json.loads(text_data) 
        message = text_data_json['message'] 
 
        request = HttpRequest() 
        request.method = 'POST' 
        request.session = self.scope["session"] 
        request = Request(request) 
        for key, val in message.items(): 
            request.data[key] = val 
 
        queue = asyncio.Queue() 
        sender = asyncio.ensure_future(self._send_msg(queue)) 
 
        await self._source1_handler(request, queue) 
        await self._source2_handler(request, queue) 
 
        await queue.join() 
 
        sender.cancel() 

如何让消息发送部分真正异步?

请您参考如下方法:

您未显示的 async_post 代码可能是同步的。

如果您想要异步请求,请参阅此答案:

https://stackoverflow.com/a/22414756/10840818

To use requests (or any other blocking libraries) with asyncio, you can use BaseEventLoop.run_in_executor to run a function in another thread and yield from it to get the result.

或者替代方法来执行 http get async

async with aiohttp.ClientSession() as session: 
        async with session.get(url, headers=HEADERS, params=params) as resp: 
            data = await resp.json()