【问题标题】:Concurrent HTTP and SQL requests using async Python 3使用异步 Python 3 的并发 HTTP 和 SQL 请求
【发布时间】:2020-04-30 18:26:24
【问题描述】:

第一次尝试asyncioaiohttp。 我有以下代码从MySQL 数据库中获取urls 以获取GET 请求。获取响应并将它们推送到MySQL 数据库。

if __name__ == "__main__":
    database_name = 'db_name'
    company_name = 'company_name'

    my_db = Db(database=database_name) # wrapper class for mysql.connector
    urls_dict = my_db.get_rest_api_urls_for_specific_company(company_name=company_name)
    update_id = my_db.get_updateid()
    my_db.get_connection(dictionary=True)

    for url in urls_dict:
        url_id = url['id']
        url = url['url']
        table_name = my_db.make_sql_table_name_by_url(url)
        insert_query = my_db.get_sql_for_insert(table_name)
        r = requests.get(url=url).json() # make the request
        args = [json.dumps(r), update_id, url_id]
        my_db.db_execute_one(insert_query, args, close_conn=False)

    my_db.close_conn()

这很好用,但要加快速度 我怎样才能运行它asynchronously

我看过hereherehere,但似乎无法理解它。

这是我根据@Raphael Medaer 的回答尝试过的。

async def fetch(url):
    async with ClientSession() as session:
        async with session.request(method='GET', url=url) as response:
            json = await response.json()
            return json


async def process(url, update_id):
    table_name = await db.make_sql_table_name_by_url(url)
    result = await fetch(url)
    print(url, result)

if __name__ == "__main__":
    """Get urls from DB"""
    db = Db(database="fuse_src")
    urls = db.get_rest_api_urls()  # This returns list of dictionary
    update_id = db.get_updateid()
    url_list = []
    for url in urls:
        url_list.append(url['url'])
    print(update_id)
    asyncio.get_event_loop().run_until_complete(
        asyncio.gather(*[process(url, update_id) for url in url_list]))

process 方法出现错误:

TypeError: object str can't be used in 'await' expression

不确定是什么问题?

任何特定于此的代码示例都将受到高度赞赏。

【问题讨论】:

  • 尝试commit所有查询和execute仅一次。
  • 感谢@Frank 任何代码fragments 将不胜感激?
  • 对不起,我真的忘了怎么做。我之前也遇到过同样的问题,我只记得我所做的是追加所有查询并一次发送到服务器。

标签: python python-asyncio aiohttp


【解决方案1】:

使这段代码异步根本不会加速它。除非您考虑“并行”运行部分代码。例如,您可以“同时”运行多个(SQL 或 HTTP)查询。通过进行异步编程,您将不会“同时”执行代码。虽然在等待 IO 时执行长 IO 任务会受益于执行代码的其他部分。

首先,您必须使用异步库(而不是同步库)。

  • mysql.connector 可以替换为来自 aio-libs 的 aiomysql
  • requests 可以替换为 aiohttp

要“并行”执行多个异步任务(例如替换循环for url in urls_dict:),您必须仔细阅读asyncio tasks 和函数gather

我不会(重新)以异步方式编写您的代码,但是这里有几行伪代码可以帮助您:

async def process(url):
    result = await fetch(url)
    await db.commit(result)

if __name__ == "__main__":
    db = MyDbConnection()
    urls = await db.fetch_all_urls()

    asyncio.get_event_loop().run_until_complete(
        asyncio.gather(*[process(url) for url in urls]))

【讨论】:

  • 这非常有用。将尝试并报告回来。谢谢@Raphael Medaer :)
  • 我在获得 url 结果方面取得了很好的成功,但在 db 方面却遇到了困难:(
  • 我看到您的编辑出现错误。但是,如果没有完整的堆栈跟踪,我们将无法帮助您。能不能把db.make_sql_table_name_by_url(url)write a minimal reproducible example的代码也放上来?
  • 上述错误是由于db.make_sql_table_name_by_url(url)方法不是async lol。我修好了它,它工作正常。我现在遇到的问题是如果db.make_sql_table_name_by_url(url) 在同一个文件中,它可以工作。但是如果我用它创建一个包装类。它给了AttributeError: module 'asyncio.streams' has no attribute 'IncompleteReadError'
  • 好的。我想我们可以考虑这个题外话或作为另一个问题。我希望我的回答能帮助您更好地了解全局。完成后,您能否给出一个完整的工作示例?并可选择接受答案?亲切的问候,
猜你喜欢
  • 1970-01-01
  • 2012-04-03
  • 1970-01-01
  • 1970-01-01
  • 2015-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多