使用 FastAPI 计算具有全局变量的请求数

Posted

技术标签:

【中文标题】使用 FastAPI 计算具有全局变量的请求数【英文标题】:Count number of requests with global variable using FastAPI 【发布时间】:2021-07-10 21:00:13 【问题描述】:

我要统计特定 URL 路径中的请求数。

app = FastAPI()
counter = 0

@app.get("/do_something")
async def do_something():
    global counter
    counter += 1
    return "message": "Hello World"

这段代码可以吗? 计数器应该是线程安全的?安全吗? 这是计算请求的正确方法(没有数据库)吗? 在这种情况下,“do_something”函数中的“async”是否有意义? 以及如何让它与多个工人一起工作?

【问题讨论】:

FastAPI 基于 asyncio,而不是线程。 相关***.com/questions/65686318/… 【参考方案1】:

此代码不安全,因为您没有使用锁。我想你认为 += 操作是原子的,所以在没有锁的情况下使用是安全的,但事实并非如此。为了保护你的状态,你需要锁。 asyncio 库提供锁https://docs.python.org/3/library/asyncio-sync.html

import asyncio

app = FastAPI()
counter = 0
lock = asyncio.Lock()

@app.get("/do_something")
async def do_something():
    global counter

    async with lock:
        counter += 1
        # some other thread-safe code here

    return "message": "Hello World"

【讨论】:

谢谢,asycio.Lock() 版本运行良好,即使在异步端点处理程序中也是如此。 ?【参考方案2】:

根据This issue,非异步端点将在线程池中处理。

非异步 def 端点(即普通 def 端点)在线程池中执行,因此如果您对共享全局对象或类似对象进行修改,可能会遇到线程安全问题。

如果它使用线程锁,那么是的,那很好。它会阻止任何其他线程接触那个东西,直到第一个线程完成,所以没关系。

所以代码可能是这样的:

import threading

app = FastAPI()
counter = 0
lock = threading.Lock()

@app.get("/do_something")
def do_something():
    global counter

    with lock:
        counter += 1
        # some other thread-safe code here

    return "message": "Hello World"

【讨论】:

【参考方案3】:

如果你使用 1 个 worker,你应该使用 asyncio 锁,因为 fastAPI 是异步的。

import asyncio

app = FastAPI()
counter_lock = asyncio.Lock()
counter = 0

@app.get("/do_something")
async def do_something():
    global counter

    async with counter_lock:
        counter += 1

    return "message": "Hello World"

但是,如果有超过 1 个工作人员无法工作,因为他们不共享相同的内存。应该使用缓存机制或数据库,正如here 解释的那样。

【讨论】:

以上是关于使用 FastAPI 计算具有全局变量的请求数的主要内容,如果未能解决你的问题,请参考以下文章

使用具有共享全局变量的线程

异步请求的数据,并将数据赋值给全局变量的一些解决方法

全局变量和 Python 多处理 [重复]

利用JavaScript打印出Fibonacci数(不使用全局变量)

vue使用全局变量来定义axios请求地址

vue使用全局变量来定义axios请求地址