如何异步运行数据库请求?

时间:2019-05-14 06:06:12

标签: python python-3.x python-asyncio aiohttp

运行此命令时,它会使用响应代码逐一列出数据库中的网站,而浏览一个很小的列表大约需要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 个答案:

答案 0 :(得分:1)

This article解释了详细信息。您需要做的是在Future对象中传递每个访存调用,然后根据需要将这些列表传递给asyncio.waitasyncio.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()通话吗?文档提到了

  

调用此函数时,循环不得运行。任何待处理的回调都将被丢弃。

     

此方法清除所有队列并关闭执行程序,但不等待执行程序完成。


正如docs和@ user4815162342发布的链接中所提到的,当我们知道该参数是a时,最好使用create_task方法而不是ensure_future方法。协程。请注意,它是在Python 3.7中添加的,因此以前的版本应继续使用ensure_future