Создайте один общий asyncio.Lock для защищаемого состояния и поместите всю проверку и изменение внутрь async with lock. Новый Lock на каждый запрос не защитит ничего, потому что запросы не будут разделять блокировку.
Вы хорошо объяснили проблему гонки и роль await. А как бы вы реализовали защиту этой составной операции с помощью асинхронного лока в FastAPI?
Создайте один общий asyncio.Lock для защищаемого состояния и поместите всю проверку и изменение внутрь async with lock. Новый Lock на каждый запрос не защитит ничего, потому что запросы не будут разделять блокировку.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Создайте один общий asyncio.Lock для защищаемого состояния и поместите всю проверку и изменение внутрь async with lock. Новый Lock на каждый запрос не защитит ничего, потому что запросы не будут разделять блокировку.
Учебный вариант для одного процесса и event loop:
import asyncio
class Account:
def __init__(self, balance):
self.balance = balance
self.lock = asyncio.Lock()
async def withdraw(self, amount):
if type(amount) is not int or amount <= 0:
raise ValueError('Invalid amount')
async with self.lock:
if self.balance < amount:
raise ValueError('Insufficient funds')
self.balance -= amount
return self.balance
Экземпляр Account должен быть общим для запросов. Такой лок не координирует разные FastAPI workers; для баланса в БД нужна атомарная операция БД. Сетевую работу без необходимости внутри критической секции не выполняют.