Setup:
- FastAPI-Version: 0.95.1
- SQLAlchemy-Version: 2.0.19
- Datenbank: SQLite
- PyNest-Version: 0.1.0
- Asynchrone Version: ~500 Sekunden für 1000 Anfragen
- Synchronische Version: 0,72 Sekunden für 1000 Anfragen
Code: Select all
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()
Code: Select all
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
Code: Select all
@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()
Code: Select 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()
Ich verwende das folgende Testskript, um 1000 Anfragen an beide Versionen zu senden:
Code: Select all
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())
Ich bin verwirrt über den großen Leistungsunterschied zwischen den beiden Versionen. Die asynchrone Version, von der ich eine schnellere oder zumindest vergleichbare Leistung erwartet hatte, ist deutlich langsamer. Was könnte die Ursache für einen solchen Leistungsunterschied zwischen der synchronen und der asynchronen Version derselben Anwendung sein?
Alle Erkenntnisse oder Vorschläge dazu, was zu diesem Problem beitragen könnte und wie die asynchrone Version optimiert werden kann, wären sehr willkommen.
Mobile version