Python 之 ContextVar协程的local 笔记

ContextVar 笔记

为什么会有ContextVar

多线程环境中,共享变量会导致线程安全问题,python 为了解决这个问题,为线程提供了local 这个对象,他是每个线程私有,在多线程环境下,每个线程的local 中存放的变量是相互隔离的,彼此不影响。
而协程是运行在线程中的,一个线程可以运行多个协程。如果是用local 就会出现多协程共享变量,这里的情况就跟对线程一样了,为了解决协程之间共享变量,于是就有了ContextVar。

ContextVar 的方法

通过源码查看类结构发现ContextVar 提供了三个方法分别是:
在这里插入图片描述
下面用表格记录一下3个方法的用途

方法作用使用场景
ContextVar.get()获取当前上下文的值读取当前环境配置
ContextVar.set()设置新值并返回Token进入新上下文环境
ContextVar.reset()恢复到指定Token之前的状态退出子上下文环境

下面通过代码演示:

import threading
import asyncio
import contextvars

local_data = threading.local()
ctx_var = contextvars.ContextVar("ctx_data")

async def coro_task(name):
    local_data.value = name
    token = ctx_var.set(name)
    try:
        await asyncio.sleep(0.1)
        print(f"协程{name}获取local_data值: {local_data.value}")
        print(f"协程{name}获取ctx_var值: {ctx_var.get()}")
        print("=="*10)
    finally:
        ctx_var.reset(token)

async def main():
    token = ctx_var.set("main")
    try:
        await asyncio.gather(

            coro_task("A"),
            coro_task("B")
        )
        print(f"协程main获取ctx_var值: {ctx_var.get()}")
    finally:
        ctx_var.reset(token)

asyncio.run(main())

输出:

协程A获取local_data值: B
协程A获取ctx_var值: A
====================
协程B获取local_data值: B
协程B获取ctx_var值: B
====================
协程main获取ctx_var值: main

通过输出日志可以发现,使用local 出现了共享问题。 A 原本是想获取local中自己设置的A 的。结果因为阻塞等待,让B 将local中的值修改为B.。而当A 在唤醒的时候,读到的是B 而不是自己设置的A了。而使用ContextVar就不会出现共享问题。

而 ctx_var.reset(token) 是退出token 对应的设置,

async def main():
    token = ctx_var.set("main1")
    try:
        print(f"第一次获取ctx_var值: {ctx_var.get()}") #第一次获取ctx_var值: main1
        token2 = ctx_var.set("main2")
        print(f"第二次获取ctx_var值: {ctx_var.get()}") # 第二次获取ctx_var值: main2
        token3 = ctx_var.set("main3")
        print(f"第三次获取ctx_var值: {ctx_var.get()}") # 第三次获取ctx_var值: main3
        ctx_var.reset(token2) # 退出 回到上一次设置的值
        print(f"第四次获取ctx_var值: {ctx_var.get()}") # 第三次获取ctx_var值: main1
    finally:
        ctx_var.reset(token)

asyncio.run(main())

通过代码可以看出。使用tx_var.reset(token) 可以将tx_var回滚到指定token 生成前的值。

注意:ContextVar 不会像local一样自动释放,而是需要手动执行reset方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值