使用 FastAPI 计算全局变量的请求数
Count number of requests with global variable using FastAPI
我想计算特定 URL 路径中的请求数。
app = FastAPI()
counter = 0
@app.get("/do_something")
async def do_something():
global counter
counter += 1
return {"message": "Hello World"}
这段代码可以吗?
计数器应该是线程安全的?安全吗?
这是计算请求的正确方法(没有数据库)吗?
在这种情况下,“do_something”函数中的“async”是否有意义?
以及如何让它与多个工人一起工作?
根据This issue,非异步端点将在线程池中处理。
Non-async def endpoints (i.e., 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.
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.
所以代码可以是这样的:
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"}
此代码不安全,因为您没有使用锁。我想你认为 += 操作是原子的,所以没有锁使用是安全的,但事实并非如此。为了保护您的状态,您需要锁。 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"}
如果您使用 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 个 worker 将无法工作,因为他们不共享相同的内存。应该使用缓存机制或数据库,如解释的那样。
我想计算特定 URL 路径中的请求数。
app = FastAPI()
counter = 0
@app.get("/do_something")
async def do_something():
global counter
counter += 1
return {"message": "Hello World"}
这段代码可以吗? 计数器应该是线程安全的?安全吗? 这是计算请求的正确方法(没有数据库)吗? 在这种情况下,“do_something”函数中的“async”是否有意义? 以及如何让它与多个工人一起工作?
根据This issue,非异步端点将在线程池中处理。
Non-async def endpoints (i.e., 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.
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.
所以代码可以是这样的:
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"}
此代码不安全,因为您没有使用锁。我想你认为 += 操作是原子的,所以没有锁使用是安全的,但事实并非如此。为了保护您的状态,您需要锁。 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"}
如果您使用 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 个 worker 将无法工作,因为他们不共享相同的内存。应该使用缓存机制或数据库,如解释的那样