-
Notifications
You must be signed in to change notification settings - Fork 2k
[aiohttp] Tweaks #9783
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[aiohttp] Tweaks #9783
Conversation
@Dreamsorcerer Great work! Sorry I didn't see your pull request prior updating mine #9767
Update: I've re-read documentation and now I am not sure that example above give any benefits comparing to
1.1) And for some reason Would you like to pick up this also? Or it is better to create a separate PR for that.
|
To my previous comment.
import os
import time
import asyncio
from typing import Callable, Awaitable
from sqlalchemy import URL, select, bindparam, lambda_stmt
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase):
pass
class World(Base):
__tablename__ = 'world'
id: Mapped[int] = mapped_column(primary_key=True)
randomnumber: Mapped[int]
def pg_dsn() -> str:
return URL.create(
drivername='postgresql+asyncpg',
username=os.getenv('PGUSER', 'postgres'),
password=os.getenv('PGPASS', 'postgres'),
host='localhost',
port='5432',
database='segment',
).render_as_string(hide_password=False)
READ_SELECT_ORM = select(World)
READ_SELECT_BIND_PARAM = select(World).where(World.id == bindparam("id"))
READ_SELECT_LAMBDA_BIND_PARAM = lambda_stmt(lambda: select(World).where(World.id == bindparam("id")))
def get_session():
engine = create_async_engine(pg_dsn(), pool_size=10)
return async_sessionmaker(engine)()
async def run_orm_select(session: AsyncSession, i: int) -> None:
await session.scalar(READ_SELECT_ORM.where(World.id == i))
async def run_bind_param(session: AsyncSession, i: int) -> None:
await session.scalar(READ_SELECT_BIND_PARAM, {"id": i})
async def run_lambda_stmt(session: AsyncSession, i: int) -> None:
await session.scalar(READ_SELECT_LAMBDA_BIND_PARAM, {"id": i})
async def benchmark(name: str, query_fn: Callable[[AsyncSession, int], Awaitable[None]], count: int) -> None:
start = time.time()
async with get_session() as session:
for i in range(count):
await query_fn(session, i)
duration = time.time() - start
print(f"{name}: {duration:.2f} seconds")
if __name__ == '__main__':
COUNT = 10000
asyncio.run(benchmark("ORM Select", run_orm_select, COUNT))
asyncio.run(benchmark("Bind Param", run_bind_param, COUNT))
asyncio.run(benchmark("Lambda Bind", run_lambda_stmt, COUNT)) |
Looks goods. Do you want to put that in another PR? If you want to figure out deployment with nginx (or directly exposed without nginx?) as well, that'd be great. I'd be interested what the performance difference is (if I started from scratch, I wouldn't have used gunicorn myself). |
Nginx is a large change, so I think it should be in a separate PR. I will try to add it this week. About |
Sounds good. Note that nginx is just a proxy used for security, so if possible, it probably makes sense to deploy raw without nginx and just expose the Python app directly, thus avoiding any proxy overhead.
To ensure I've got your changes correctly, can you just PR into my fork? |
Yes, sure. I've prepared PR Dreamsorcerer#1 please take a look.
That is great idea also, but I am not sure how to consume all CPU cores inside single docker container at such deployment configuration, that's why I though some kind of proxy server is required. Do you have any thoughts? |
aiohttp orm use bindparam
Ah, yes, of course. nginx makes the most sense then. |
Minor optimisation and rename the test runs to better match other frameworks (aiohttp -> aiohttp-orm, aiohttp-pg-raw -> aiohttp).