[英]FastAPI: global variable vs module variable
I would like to have a global variable limited to a FastAPI request execution but common to multiple modules.我希望有一个全局变量,仅限于 FastAPI 请求执行,但对多个模块是通用的。 Below is a small example to explain the problem:下面是一个小例子来解释这个问题:
I built a very simple app with a main file app.py and a module mymodule .我用一个主文件app.py和一个模块mymodule构建了一个非常简单的应用程序。 For each test i launch the app in uvicorn with 1 worker and then open 2 python consoles to call for long and short call requests.get("http://localhost:8000/fakelongcall", {"configtest": "long"}), requests.get("http://localhost:8000/fakeshortcall", {"configtest": "short"}).对于每个测试,我使用 1 个工作人员在 uvicorn 中启动应用程序,然后打开 2 个 python 控制台以调用长短调用 requests.get("http://localhost:8000/fakelongcall", {"configtest": "long"} ), requests.get("http://localhost:8000/fakeshortcall", {"configtest": "short"})。
First situation: it's working but the global variable GLOBAL_VAR is not in a module thus not accessible by an other module (I may be wrong on that).第一种情况:它正在工作,但全局变量 GLOBAL_VAR 不在模块中,因此其他模块无法访问(我可能错了)。
app.py应用程序.py
import time
from fastapi import FastAPI
GLOBAL_VAR = "default"
app = FastAPI()
@app.get("/fakelongcall")
def fakelongcall(configtest: str):
cpt = 0
while cpt < 10:
print(GLOBAL_VAR)
time.sleep(1)
cpt = cpt + 1
@app.get("/fakeshortcall")
def fakeshortcall(configtest: str):
GLOBAL_VAR = configtest
print("Change done !")
output output
INFO: Started server process [34182]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
default
default
Change done !
INFO: 127.0.0.1:52250 - "GET /fakeshortcall?configtest=short HTTP/1.1" 200 OK
default
default
default
default
default
default
default
default
Second situation: both calls are changing the same variable which is not expected but the variable is accessible in a module which is nice.第二种情况:两个调用都在改变同一个变量,这不是预期的,但是该变量可以在一个很好的模块中访问。
app.py应用程序.py
import time
from fastapi import FastAPI
import mymodule
app = FastAPI()
@app.get("/fakelongcall")
def fakelongcall(configtest: str):
cpt = 0
while cpt < 10:
print(mymodule.GLOBAL_VAR)
time.sleep(1)
cpt = cpt + 1
@app.get("/fakeshortcall")
def fakeshortcall(configtest: str):
mymodule.GLOBAL_VAR = configtest
print("Change done !")
mymodule.py我的模块.py
GLOBAL_VAR = "default" GLOBAL_VAR = "默认"
output output
INFO: Started server process [33994]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
default
default
default
Change done !
INFO: 127.0.0.1:52240 - "GET /fakeshortcall?configtest=short HTTP/1.1" 200 OK
short
short
short
short
short
short
short
Why is this happening?为什么会这样? How can one worker execute 2 calls simultaneously?一个工作人员如何同时执行 2 个调用? What can I do to obtain a module variable that is not shared among different API requests?如何获取不同 API 请求之间不共享的模块变量? Why embedding the same code in a module changes the behavior?为什么在模块中嵌入相同的代码会改变行为?
Thanks in advance for your help.在此先感谢您的帮助。
This is a classic pitfall when dealing with global variables.这是处理全局变量时的一个典型陷阱。 From FAQ :从常见问题解答:
In Python, variables that are only referenced inside a function are implicitly global.在 Python 中,仅在 function 内部引用的变量是隐式全局的。 If a variable is assigned a value anywhere within the function's body, it's assumed to be local unless explicitly declared as global.如果一个变量在函数体内的任何地方都被赋值,除非明确声明为全局变量,否则它被假定为局部变量。
In the second case, you are accessing a member of the imported module, which does not create a local variable.在第二种情况下,您正在访问导入模块的成员,该成员不会创建局部变量。
To fix it use the global
keyword:要修复它,请使用global
关键字:
def foo():
global GLOBAL_VAR
GLOBAL_VAR = configtest
So thanks to alex_noname .所以感谢alex_noname 。 It works with contextvars.它适用于上下文变量。
app.py应用程序.py
import time
from fastapi import FastAPI
import mymodule
app = FastAPI()
@app.get("/fakelongcall")
def fakelongcall(configtest: str):
cpt = 0
mymodule.var.set(configtest)
while cpt < 10:
print(mymodule.var.get())
time.sleep(1)
cpt = cpt + 1
@app.get("/fakeshortcall")
def fakeshortcall(configtest: str):
mymodule.var.set(configtest)
print("Change done !")
mymodule.py我的模块.py
from contextvars import ContextVar
var = ContextVar("var")
output output
INFO: Started server process [37237]
INFO: Waiting for application startup.
INFO: Application startup complete.
long
long
long
Change done !
INFO: 127.0.0.1:38680 - "GET /fakeshortcall?configtest=short HTTP/1.1" 200 OK
long
long
long
long
long
long
long
long
INFO: 127.0.0.1:38678 - "GET /fakelongcall?configtest=long HTTP/1.1" 200 OK
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.