contextvars使用

contextvars使用

flask的隐式传递

flask可以隐式传递变量(request,g),使用的是ThreadLocal(本地线程)对象,但是flask并不是使用python自带的ThreadLocal,而是自己实现了一个Local类,除了支持线程还支持了 Greenlet 的协程

Q: 那为什么不用全局变量呢? A: 由于存在 GIL,全局变量的修改必须加锁,会影响效率

contextvars

contextvars,这个模块提供了一组接口,可用于管理、储存、访问局部 Context 的状态

示例

请求前钩子

# hook.py
from contextvars import ContextVar
# 定义上下文变量
RequestID = ContextVar('request_id') 

@web.middleware
async def before_middleware(request: Request, handler):
    # 设置唯一key
    request_id = RequestID.set(str(uuid4()))
    request['request_id'] = request_id
# logger.py
import logging

class LoggerFormatter(logging.Formatter):

    def __init__(self, msg=LOG_FORMAT):
        logging.Formatter.__init__(self, msg)

    def format(self, record):
        record_clone = copy(record)
        try:
            # 全局更改,这样在多handler比如文件输出和console输出会跑两次这个函数
            from trpc_unit.aiohttp_middleware import RequestID
            unq_id = RequestID.get(None)
            record_clone.msg = "[{}] ".format(unq_id) + record_clone.msg
        except:
            pass
        return logging.Formatter.format(self, record_clone)

官方用法

上下文变量¶
class contextvars.ContextVar(name[, *, default])
此类用于声明一个新的上下文变量,如:

var: ContextVar[int] = ContextVar('var', default=42)
name 参数用于内省和调试,必需。

调用 ContextVar.get() 时,如果上下文中没有找到此变量的值,则返回可选的仅命名参数 default 。

重要: 上下文变量应该在顶级模块中创建,且永远不要在闭包中创建。 Context 对象拥有对上下文变量的强引用,这可以让上下文变量被垃圾收集器正确回收。

name
上下文变量的名称,只读属性。

3.7.1 新版功能.

get([default])
返回当前上下文中此上下文变量的值。

如果当前上下文中此变量没有值,则此方法会:

如果提供了得 话,返回传入的 default 值;或者

返回上下文变量本身的默认值, 如果创建此上下文变量时提供了默认值;或者

抛出 LookupError 异常。

set(value)
调用此方法设置上下文变量在当前上下文环境中的值。

必选参数 value 是上下文变量的新值。

返回一个 Token  对象,可通过 ContextVar.reset() 方法将上下文变量还原为之前某个状态。

reset(token)
将上下文变量重置为调用 ContextVar.set() 之前、创建 token 时候的状态。

参考链接

https://gist.github.com/messa/c538fc267550ec67a1fed244183dcf1e

https://docs.python.org/zh-cn/3.7/library/contextvars.html

本文作者:朝圣

本文链接:www.zh-noone.cn/2021/8/contextvars使用

版权声明:本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0许可协议。转载请注明出处!

python请求https出现版本异常的问题
0 条评论