Помогите понять, почему ассинхронный парсер работает синхронно
Пытаюсь разобраться с асинхронной работой... Для сравнения написал синхронный и асинхроный код для загрузки с "jsonplaceholder" и сохранения в PostgreSQL. Вот только мой синхронный код работает, вопреки ожиданиям, быстрее асинхронного. Подскажите, пжл, что я не так делаю?
import asyncio
import aiohttp
from loguru import logger
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import sessionmaker
from db.models import User, Album, Photo, Todo, Post, Comment, Base
URL = 'https://jsonplaceholder.typicode.com'
async def get_data(url: str, session: aiohttp.ClientSession):
logger.info('Start {}!', url)
async with session.get(url, allow_redirects=True) as response:
data = await response.json()
logger.info('Finish {}!', url)
return data
async def create_users(session):
logger.info('Start!')
async with aiohttp.ClientSession() as httpsession:
users = await get_data(URL + '/users', httpsession)
users_lst = [User(
id=user.get('id'),
name=user.get('name'),
username=user.get('username'),
email=user.get('email'),
address=user.get('address'),
phone=user.get('phone'),
website=user.get('website'),
company=user.get('company')
) for user in users
]
session.add_all(users_lst)
logger.info('Finish!')
async def create_todos(session):
logger.info('Start!')
async with aiohttp.ClientSession() as httpsession:
todos = await get_data(URL + '/todos', httpsession)
todos_lst = [Todo(
title=todo.get('title'),
completed=todo.get('completed'),
userId=todo.get('userId')
) for todo in todos
]
session.add_all(todos_lst)
logger.info('Finish!')
async def create_albums(session):
logger.info('Start!')
async with aiohttp.ClientSession() as httpsession:
albums = await get_data(URL + '/albums', httpsession)
albums_lst = [Album(
id=album.get('id'),
title=album.get('title'),
userId=album.get('userId')
) for album in albums
]
session.add_all(albums_lst)
logger.info('Finish!')
async def create_photos(session):
logger.info('Start!')
async with aiohttp.ClientSession() as httpsession:
photos = await get_data(URL + '/photos', httpsession)
photos_lst = [Photo(
title=photo.get('title'),
url=photo.get('url'),
thumbUrl=photo.get('thumbUrl'),
albumId=photo.get('albumId')
) for photo in photos
]
session.add_all(photos_lst)
logger.info('Finish!')
async def create_posts(session):
logger.info('Start!')
async with aiohttp.ClientSession() as httpsession:
posts = await get_data(URL + '/posts', httpsession)
posts_lst = [Post(
id=post.get('id'),
title=post.get('title'),
userId=post.get('userId'),
) for post in posts
]
session.add_all(posts_lst)
logger.info('Finish!')
async def create_comments(session):
logger.info('Start!')
async with aiohttp.ClientSession() as httpsession:
comments = await get_data(URL + '/comments', httpsession)
comments_lst = [Comment(
name=comment.get('name'),
email=comment.get('email'),
body=comment.get('body'),
postId=comment.get('postId')
) for comment in comments
]
session.add_all(comments_lst)
logger.info('Finish!')
async def async_main():
engine = create_async_engine(
"postgresql+asyncpg://karomag:password@localhost/sync_vs_async"
)
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.drop_all)
await conn.run_sync(Base.metadata.create_all)
async_session = sessionmaker(
engine, expire_on_commit=False, class_=AsyncSession
)
coros = [
create_users,
create_todos,
create_albums,
create_posts,
create_photos,
create_comments,
]
async with async_session() as session:
async with session.begin():
tasks = []
for func in coros:
task = asyncio.create_task(func(session))
tasks.append(task)
await asyncio.gather(*tasks)
await engine.dispose()
if __name__ == '__main__':
logger.info('Start the async version!')
asyncio.run(async_main())
logger.info('Finish the async version!')
Если посмотреть на логи:
2021-11-22 21:03:35.106 | INFO | __main__:<module>:143 - Start the async version!
2021-11-22 21:03:35.267 | INFO | __main__:create_users:21 - Start!
...
2021-11-22 21:03:35.906 | INFO | __main__:create_photos:79 - Finish!
2021-11-22 21:03:40.543 | INFO | __main__:<module>:145 - Finish the async version!
Можно заметить, что все корутины выполняются за 1сек, а остальные 5сек, как я понял, это комит и закрытие сессии, и await engine.dispose()?
Ответы (1 шт):
Автор решения: Munchen777
→ Ссылка
Во-первых, советовал бы вам сделать рефакторинг кода: создание движка и асинхронной сессии вынести в отдельный файл. Во-вторых, вы используете не асинхронную сессию:
from sqlalchemy.ext.asyncio import async_sessionmake
async_session = async_sessionmaker(async_engine)