You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 09:52:34