Почему синхронный сеанс SQLAlchemy быстрее, чем асинхронный в FastAPIPython

Программы на Python
Ответить
Anonymous
 Почему синхронный сеанс SQLAlchemy быстрее, чем асинхронный в FastAPI

Сообщение Anonymous »

Я работаю с двумя версиями приложения FastAPI: одна использует асинхронное соединение с базой данных SQLAlchemy, а другая — синхронное соединение. Удивительно, но я наблюдаю, что синхронная версия значительно превосходит асинхронную во время тестов производительности.
Настройка:
  • Версия FastAPI: 0.95.1
  • Версия SQLAlchemy: 2.0.19
  • База данных: SQLite
  • Версия PyNest: 0.1.0
Результаты теста производительности:
  • Асинхронная версия: ~500 секунд для 1000 запросов
  • Синхронная версия: 0,72 секунды на 1000 запросов
Асинхронная инициализация сеанса:

Код: Выделить всё

class Config:

def __init__(self):
self.engine = create_async_engine("sqlite+aiosqlite:///finance.db", connect_args={"check_same_thread": False})
self.SessionLocal = async_sessionmaker(self.engine)
self.Base = Base

async def create_all(self):
async with self.engine.begin() as conn:
await conn.run_sync(self.Base.metadata.create_all)

async def drop_all(self):
async with self.engine.begin() as conn:
await conn.run_sync(self.Base.metadata.drop_all)

async def get_db(self):
db = self.SessionLocal()
try:
yield db
finally:
await db.close()
Синхронная инициализация сеанса:

Код: Выделить всё

class OrmService:
def __init__(self, db_type: str = "postgresql", config_params: dict = None):
self.Base = declarative_base()
self.config = ConfigFactory(db_type=db_type).get_config()
self.config_url = self.config(**config_params).get_engine_url()
self.engine = create_engine(self.config_url)

def create_all(self):
self.Base.metadata.create_all(bind=self.engine)

def drop_all(self):
self.Base.metadata.drop_all(bind=self.engine)

def get_db(self) -> Session:
try:
session = sessionmaker(bind=self.engine)
return session()
except Exception as e:
raise e
Контроллер и служба для асинхронной версии:

Код: Выделить всё

@Controller("finance")
class FinanceController:

@Get("/transactions")
async def get_transactions(self, session: AsyncSession = Depends(config.get_db)):
stmt = select(Transaction)
query = await session.execute(stmt)
return query.scalars().all()
Контроллер и служба для версии синхронизации:

Код: Выделить всё

@Controller("transaction", prefix="transaction")
class TransactionController:
service: TransactionService = Depends(TransactionService)

@Get("/")
def get_transactions(self):
return self.service.get_transactions()

@lru_cache()
class TransactionService:
def __init__(self):
self.orm_config = config
self.session = self.orm_config.get_db()

def get_transactions(self):
return self.session.query(TransactionEntity).first()
Процедура тестирования:
Я использую следующий тестовый сценарий для отправки 1000 запросов к обеим версиям:

Код: Выделить всё

import asyncio
import aiohttp
import time

async def fetch(session, url):
start_time = time.time()
async with session.get(url) as response:
response_text = await response.text()
end_time = time.time()
print(f"URL: {url} - Start: {start_time:.2f}, End: {end_time:.2f}, Duration: {end_time - start_time:.2f} seconds")
return response_text

async def main():
s = time.time()
urls = ["http://0.0.0.0:8088/transactions"] * 1000
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, url) for url in urls]
responses = await asyncio.gather(*tasks)
print(len(responses))
print("response have been gathered")
print(f"Total time: {time.time() - s:.2f}")

# Run the main coroutine
asyncio.run(main())
Вопрос:
Меня озадачивает огромная разница в производительности между двумя версиями. Асинхронная версия, от которой я ожидал большей производительности или, по крайней мере, сопоставимой по производительности, оказалась значительно медленнее. Что может быть причиной такого несоответствия в производительности между синхронной и асинхронной версиями одного и того же приложения?
Будем очень признательны за любые идеи или предложения о том, что может способствовать этой проблеме и как оптимизировать асинхронную версию.

Подробнее здесь: https://stackoverflow.com/questions/775 ... in-fastapi
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»