我对asyncio和ContextVars
完全陌生,我只是阅读了3.7中的新增功能并发现了ContextVars
,我很难理解它的用法,我知道它在协程中很有用,而不是使用thread.local
应该使用ContextVars
。但是,官方文档和google顶级搜索结果都无法帮助我真正理解其目的。
那么converttvars是否在模块之间共享?我尝试过:
example.py
from contextvars import ContextVar
number = ContextVar('number', default=100)
number.set(1)
然后我尝试导入number.py
(playground) Jamess-MacBook-Pro-2:playground jlin$ python3.7
Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 26 2018, 23:26:24)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import example
>>> from contextvars import ContextVar
>>> number = ContextVar('number', default=200)
>>> number.get()
200
我期望number.get()
返回1,但显然我理解它的目的是错误的。
有人可以帮我理解吗?
答案 0 :(得分:1)
假设您的用例是使用python thread.local
在多线程应用程序中存储线程全局变量。
例如,您在request
thread.local
request
实例想象不到您将asyncio中的HTTP请求作为在同一python线程中执行的非阻塞代码来处理。
thread.local
中的HTTP请求将无法正常工作,因为在同一个python线程中处理了多个并发请求thread.local
变量,并且您的所有代码都可以访问最新的(错误的)request
实例在这种情况下,您将使用ContextVars
设计用于此用例,以在同一python线程中运行的非阻塞并发作业中使用。
答案 1 :(得分:0)
您已再次为数字指定值。这就是为什么它显示最新更新中的200。
答案 2 :(得分:0)
您正在重新分配number
的值。从模块直接调用变量,例如example.number.get()
。
一个简单的应用程序正在替换全局变量。
给出
import random
import contextvars as cv
代码
在这里,我们将模仿随机行走。像全局变量一样,我们能够在函数之间共享状态:
move = cv.ContextVar("move", default="")
def go_left():
value = move.get()
move.set(value + "L")
def go_right():
value = move.get()
move.set(value + "R")
def random_walk(steps):
directions = [go_left, go_right]
while steps:
random.choice(directions)()
steps -= 1
return move.get()
演示
ContextVar
充当全局变量,该变量由随机事件更新:
random_walk(1)
# 'R'
random_walk(2)
# 'RLL'
random_walk(3)
# 'RLLLRL'
除了常规的全局变量ContextVar
:
答案 3 :(得分:0)
不能完全确定我的方法是否正确,但是我将添加调查结果以作答,因此我尝试在django项目中使用它来设置request
var,而不使用本地线程。
from contextvars import ContextVar
request_var = ContextVar('request', default=None)
def request_middleware(get_response):
"""
Sets the request into contextvar
"""
def middleware(request):
ctx = copy_context()
return ctx.run(wrap_get_response, request)
def wrap_get_response(request):
request_var.set(request)
return get_response(request)
return middleware
然后将其放在需要使用request
var的其他地方:
from core.middlewares import request_var
request = request_var.get()
不确定这是否正确使用,但对我来说似乎正常。
我不知道如何从context.get()中获取request_var。
from contextvars import copy_context
ctx = copy_context()
# the key here is `request_var` obj in middlewares.py,
# might as well just import `request_var` and use it directly?
request = ctx.get(...)