Вопрос по асинхронному запросу к Postgresql, получение результатов
Коллеги, совершенно не понимаю в асинхронном программировании, хочу разобраться, прошу помощи. У меня написан проект с использованием библиотеки psycopg2
, в качестве интерфейса для Postgresql. Я решил добавить в проект асинхронности, обновил модуль до psycopg
версии 3, который поддерживает асинхронность и написал простенький пример, чтобы проиллюстрировать мои вопросы.
import asyncio
import psycopg
from datetime import datetime
async def main():
async def open_connection():
async with await psycopg.AsyncConnection.connect(
dbname=dbname,
password=password,
host='localhost') as aconn:
async with aconn.cursor() as cur:
await cur.execute("select count(*) from table_1 join table_2 using (id)")
print("\nВыполнили запрос к БД")
return await cur.fetchall()
async def print_monitor():
while True:
print(f'\r{datetime.now()}', end='')
await asyncio.sleep(0)
async with asyncio.TaskGroup() as tg:
task1 = tg.create_task(open_connection())
task2 = tg.create_task(print_monitor())
asyncio.run(main())
В примере две корутины - первая запрашивает базу, вторая постоянно печатает время (просто счетчик времени). Когда ответ на запрос возвращен базой, печатаем "Выполнили...".
Вопросы (Если требуется разбить на два отдельных вопроса - напишите в коментах)
- В синхронном коде метод
cursor.fetchall()
возвращает ответ базы (обычно это список кортежей). В асинхронном варианте он возвращает корутину. Как получить результат? - Как видно из кода, вывод времени не остановится, когда запрос в базу будет выполнен. Есть ли специальные методы в модуле
asyncio
или еще где-то, чтобы получить подтверждение выполнения корутины и, как только она будет выполнена, прервать счетчик. Т. е., мне это видится так, что в условииwhile
должен быть некий флаг, срабатывающий по выполнении корутины запроса к базе. Я могу, конечно, ввестиnonlocal
переменную вmain()
и использовать ее в качестве флага, но что-то мне подсказывает, что должны быть какие-то асинхронные инструменты.
UPT
Чуть изменю первый вопрос. Во всех доках и примерах написано, что и в асинхронном коде cursor.fetchall()
должен вернуть результат. А у меня он возвращает корутину, значит что-то я не так написал. Что?
Ответы (1 шт):
Используйте asyncio.Event()
и task.result()
:
import asyncio
import psycopg
from datetime import datetime
async def main():
async def open_connection(event):
async with await psycopg.AsyncConnection.connect(
dbname=dbname,
password=password,
host='localhost') as aconn:
async with aconn.cursor() as cur:
await cur.execute("select count(*) from table_1 join table_2 using (id)")
print("\nВыполнили запрос к БД")
event.set()
return await cur.fetchall()
async def print_monitor(event):
while not event.is_set():
print(f'\r{datetime.now()}', end='')
await asyncio.sleep(0)
event = asyncio.Event()
async with asyncio.TaskGroup() as tg:
task1 = tg.create_task(open_connection(event))
task2 = tg.create_task(print_monitor(event))
print(task1.result())
asyncio.run(main())