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

为何Python中ContextVar在该echo服务器场景下能正常工作?

问题:为何这段使用ContextVar的echo服务器能正常工作?

以下是一个可正常运行的echo服务器——这里的“正常”指输出显示每个用户在listen_for_messages中能获取到唯一的地址:

import asyncio
from contextvars import ContextVar


class Server:
    user_address = ContextVar("user_address")

    def __init__(self, host: str, port: int):
        self.host = host
        self.port = port

    async def start_server(self):
        server = await asyncio.start_server(self._on_connected, self.host, self.port)
        await server.serve_forever()

    def _on_connected(self, reader, writer):
        self.user_address.set(writer.get_extra_info("peername"))
        asyncio.create_task(self.listen_for_messages(reader))

    async def listen_for_messages(self, reader):
        while data := await reader.readline():
            print(f"Got message {data} from {self.user_address.get()}")

async def main():
    server = Server("127.0.0.1", 9000)
    await server.start_server()

asyncio.run(main())

我的疑问是:为何这段代码能正常工作?

我原本的理解是每个Task拥有独立的ContextVar副本。若语句:

self.user_address.set(writer.get_extra_info("peername"))

位于listen_for_messages协程内(已显式创建新Task),或是_on_connected为协程函数(根据官方文档,协程函数会被自动调度为Task),我都不会有疑问。但该语句位于普通函数_on_connected中,此时还未创建listen_for_messages的新Task,属于main()创建的父Task,我认为会覆盖ContextVar的值,但实际却正常运行,想知道我的理解误区在哪里?


解答

核心误区在于你对asyncio.start_server调用_on_connected的时机和上下文理解有误——_on_connected并不是在main的父Task里执行的。

当asyncio.start_server启动的服务器接收到新连接时,它会为每个新连接单独创建一个临时Task来执行_on_connected函数。也就是说,每个客户端连接触发的_on_connected都运行在独立的Task上下文里,并非共享main的那个Task。

这样一来,每个_on_connected里调用self.user_address.set()设置的ContextVar值,都是当前独立Task的专属副本。而后续通过asyncio.create_task()创建的listen_for_messages Task,会自动继承当前_on_connected所在Task的上下文——这是asyncio的Task上下文继承规则:新创建的Task会复制父Task的ContextVar状态。

所以每个listen_for_messages Task拿到的都是对应连接的地址,不会被其他连接覆盖。

总结关键点:

  • 每个新连接的_on_connected都运行在独立Task中,各自的ContextVar互不干扰
  • 新创建的listen_for_messages Task继承了对应_on_connected的上下文,能获取正确的地址

内容的提问来源于stack exchange,提问作者S.B

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 16:25:11