aiohttp多用户访问时出现实例变量值共享是什么原因?
问题结论
该现象和aiohttp的运行模式无关,是类实例的使用方式错误导致的。
原因说明
你在模块导入阶段、全局作用域下实例化的对象,是服务进程内全局共享的单例。aiohttp默认通过web.run_app启动时是单进程异步模型,所有用户请求的处理协程都运行在同一个事件循环中,共享进程内的所有全局对象:
- 单用户访问时,所有操作都作用在这一个实例上,逻辑不会出现异常
- 多用户并发访问时,任意一个请求调用
instance.changevalue()修改的都是这份全局共享的实例属性,修改结果会被所有后续请求(包括其他用户发起的请求)直接读取,自然就会出现跨设备的状态串扰问题。
修复方案
不要在全局作用域实例化存储用户状态的可变对象,根据业务场景选择对应实现:
- 如果实例状态不需要跨请求保留:直接在每个路由处理函数内部做实例化,每个请求持有独立的实例,请求处理完成后实例自动回收,完全不会出现跨请求污染
from aiohttp import web # 仅定义类,不要在全局作用域实例化 class StateClass: def __init__(self): self.user_value = 0 def changevalue(self, val): self.user_value = val async def route_handler(request): # 每个请求进来创建专属实例 req_instance = StateClass() # 后续业务逻辑操作当前请求的req_instance即可 return web.Response(text=f"current value: {req_instance.user_value}") app = web.Application() app.add_routes([web.get("/", route_handler)]) if __name__ == "__main__": web.run_app(app) - 如果需要在同个用户的多个请求间保留状态:基于会话ID做状态隔离,把不同用户的状态存在独立的会话存储中,不要把状态直接挂在全局对象上。
补充:异步服务开发中要特别注意,所有全局作用域的可变对象都是跨请求共享的,任何修改都会影响所有并发请求,涉及用户专属状态的对象一定要做请求/会话级别的隔离。
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

