Django Channels页面加载卡顿求助:Redis阻塞引发页面无响应
问题根源与解决方案
嘿,我一眼就看出问题所在了——你的代码里有个同步阻塞操作直接卡死了ASGI事件循环!让我给你拆解一下:
为什么会卡顿?
你写的receive方法是同步方法(没有async修饰),而且里面的pubsub.listen()是一个无限循环的同步阻塞调用。Django Channels基于ASGI运行,整个应用的事件循环是单线程的,这个循环被你的无限阻塞操作占死之后,其他所有请求(包括页面切换、新的WebSocket连接)都没法被处理,自然就会出现页面加载卡顿的情况。
另外,你在websocket_connect里直接调用self.receive(event),这也是同步调用,会直接把连接阶段的流程卡住,导致WebSocket握手完成后整个进程都被占住。
修复方案:用异步Redis客户端 + 异步任务监听
我们需要改用异步Redis客户端(比如aioredis),并且把监听Redis频道的逻辑放到一个独立的异步任务里,这样不会阻塞主事件循环。
步骤1:安装异步Redis库
先安装aioredis:
pip install aioredis
步骤2:修改消费者代码
下面是修复后的完整代码,我会逐行解释关键改动:
import asyncio import aioredis from channels.generic.websocket import AsyncWebsocketConsumer class EchoConsumer(AsyncWebsocketConsumer): async def connect(self): # 先完成WebSocket握手 await self.accept() # 初始化异步Redis连接 self.redis = await aioredis.from_url( "redis://localhost:6379/0", decode_responses=True ) # 订阅目标频道 self.pubsub = self.redis.pubsub() await self.pubsub.subscribe("TEST") # 启动一个异步任务来监听Redis消息,避免阻塞主循环 self.listen_task = asyncio.create_task(self.listen_redis_messages()) async def listen_redis_messages(self): try: # 异步迭代接收Redis消息 async for message in self.pubsub.listen(): # 忽略订阅确认消息 if message["type"] != "message": continue # 异步发送消息到前端 await self.send(text_data=message["data"]) except asyncio.CancelledError: # 任务被取消时(比如WebSocket断开),清理资源 await self.pubsub.unsubscribe("TEST") await self.pubsub.close() await self.redis.close() async def disconnect(self, close_code): # 取消监听任务,触发资源清理 self.listen_task.cancel() await self.listen_task print('DISCONNECTED!')
关键改动说明
- 改用
AsyncWebsocketConsumer:这是Django Channels提供的更简洁的异步WebSocket消费者基类,比AsyncConsumer更贴合WebSocket场景。 - 异步Redis操作:用
aioredis的异步API替代同步的redis.StrictRedis,所有Redis相关操作都是await的,不会阻塞事件循环。 - 独立异步任务:把监听Redis消息的逻辑放到
listen_redis_messages异步方法里,用asyncio.create_task启动,这样主事件循环可以继续处理其他请求。 - 资源清理:在断开连接时取消监听任务,确保Redis订阅和连接被正确关闭,避免资源泄漏。
额外注意事项
- 永远不要在AsyncConsumer的异步方法里调用同步阻塞代码(比如同步Redis库的操作、
time.sleep()等),必须用对应的异步版本。 - 如果需要处理多个频道或者复杂的Redis操作,记得保持所有IO操作都是异步的。
- 测试时可以先在前端打开WebSocket连接,然后用Redis客户端往
TEST频道发消息,看看前端能不能实时收到。
内容的提问来源于stack exchange,提问作者Jack022
相关产品推荐
相关产品推荐

