Как выполнять запросы к БД асинхронно? - PullRequest
0 голосов
/ 14 мая 2019

Когда я запускаю это, он перечисляет сайты в базе данных один за другим с кодом ответа, и для прохождения очень маленького списка требуется около 10 секунд.Это должно быть намного быстрее и не работает асинхронно, но я не уверен, почему.

import dblogin
import aiohttp
import asyncio
import async_timeout

dbconn = dblogin.connect()
dbcursor = dbconn.cursor(buffered=True)
dbcursor.execute("SELECT thistable FROM adatabase")
website_list = dbcursor.fetchall()

async def fetch(session, url):
    with async_timeout.timeout(30):
        async with session.get(url, ssl=False) as response:
            await response.read()
            return response.status, url

async def main():
    async with aiohttp.ClientSession() as session:
        for all_urls in website_list:
            url = all_urls[0]
            resp = await fetch(session, url)
            print(resp, url)

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
    loop.close()

dbcursor.close()
dbconn.close()

1 Ответ

1 голос
/ 14 мая 2019

Эта статья объясняет детали. Что вам нужно сделать, это передать каждый вызов выборки в Future объекте, а затем передать список из них либо asyncio.wait или asyncio.gather в зависимости от ваших потребностей.

Ваш код будет выглядеть примерно так:

async def fetch(session, url):
    with async_timeout.timeout(30):
        async with session.get(url, ssl=False) as response:
            await response.read()
            return response.status, url

async def main():
    tasks = []
    async with aiohttp.ClientSession() as session:
        for all_urls in website_list:
            url = all_urls[0]
            task = asyncio.create_task(fetch(session, url))
            tasks.append(task)

        responses = await asyncio.gather(*tasks)

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    future = asyncio.create_task(main())
    loop.run_until_complete(future)

Кроме того, вы уверены, что loop.close() вызов необходим? В документах упоминается, что

Цикл не должен выполняться при вызове этой функции. Все ожидающие обратные вызовы будут отброшены.

Этот метод очищает все очереди и завершает работу исполнителя, но не ожидает его завершения.


Как уже упоминалось в документах и в ссылке, размещенной @ user4815162342, лучше использовать метод create_task вместо метода ensure_future, когда мы знаем, что аргумент является сопрограммой. Обратите внимание, что это было добавлено в Python 3.7, поэтому предыдущие версии должны продолжать использовать ensure_future.

...