简体   繁体   English

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

[英]Count number of requests with global variable using FastAPI

I want to count the number of requests in a specific URL path.我想计算特定 URL 路径中的请求数。

app = FastAPI()
counter = 0

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

Is this code ok?这段代码好吗? The counter should be thread safe?计数器应该是线程安全的吗? asincio safe? asincio安全吗? Is that the right way to count requests (Without DB)?这是计算请求的正确方法(没有数据库)吗? Is there a meaning for the "async" in the "do_something" function in this situation?在这种情况下,“do_something”函数中的“async”是否有意义? And how to make it work with several workers?以及如何让它与几个工人一起工作?

According to This issue , non-async endpoints will be processed in a thread pool.根据This issue ,非异步端点将在线程池中处理。

Non-async def endpoints (ie, plain def endpoints) get executed in a threadpool, so it is possible to run into thread safety issues if you make modifications to shared global objects or similar.非异步 def 端点(即普通 def 端点)在线程池中执行,因此如果对共享全局对象或类似对象进行修改,则可能会遇到线程安全问题。

If it is that it uses a thread lock, then yeah, that's fine.如果是它使用线程锁,那么是的,那很好。 It will prevent any other thread from touching that thing until the first one finishes, so that's fine.它会阻止任何其他线程在第一个线程完成之前接触那个东西,所以没关系。

So the code could be like this:所以代码可能是这样的:

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"}

This code is unsafe because you are not using locks.这段代码是不安全的,因为你没有使用锁。 I think you thought that the += operation is atomic, so it's safe to use without locks, but it's not.我认为您认为 += 操作是原子操作,因此在没有锁的情况下使用是安全的,但事实并非如此。 To protect your state you need locks.为了保护您的状态,您需要锁。 The asyncio library provides locks https://docs.python.org/3/library/asyncio-sync.html . asyncio 库提供锁https://docs.python.org/3/library/asyncio-sync.html

import asyncio

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

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

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

    return {"message": "Hello World"}

If you're using 1 worker you ushould use an asyncio lock because fastAPI is asynchronous.如果您使用 1 个工人,您应该使用 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"}

But if there is more than 1 worker that wouldn't work because they do not share the same memory.但是,如果有 1 个以上的工人无法工作,因为他们不共享相同的内存。 Should be using a cache mechanism or a DB, As explained here .应该使用缓存机制或数据库,如解释here

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM