使用aiomysql异步连接MySQL未提速,求正确实现方法
如何正确实现MySQL的异步连接与并发查询
首先,你的异步代码没体现出异步优势的核心原因是:你是串行执行每个数据库查询任务的。在main函数里,你用了for i in range(2): await test(pool, loop),每次await都会等待当前test任务完全执行完毕才会开始下一个,这和同步循环的执行逻辑几乎一样,自然耗时和同步代码相差无几。
问题代码的核心问题
看你的main函数:
async def main(loop): pool = await aiomysql.create_pool(host='127.0.0.1', port=3306, user='root', password='qhdks12#$', db='stock', loop=loop) for i in range(2): await test(pool, loop) # 这里是串行执行,每次等前一个完成才走下一次循环
这里的循环是逐个等待任务完成,完全没利用异步IO的并发特性。
正确的异步并发实现
要真正发挥异步的优势,你需要把多个查询任务并发提交,让它们在等待数据库响应的时间里去执行其他任务。可以用asyncio.gather()来批量并发执行多个异步任务:
修改后的完整代码
import asyncio import aiomysql import pandas as pd async def test(pool): async with pool.acquire() as conn: async with conn.cursor() as cur: await cur.execute("select * from test;") rows = await cur.fetchall() return pd.DataFrame.from_records(list(rows)) async def main(): # Python 3.7+ 可以不用显式传loop,create_pool会自动获取当前事件循环 pool = await aiomysql.create_pool( host='127.0.0.1', port=3306, user='root', password='qhdks12#$', db='stock', minsize=5, # 连接池最小连接数,根据并发量调整 maxsize=10 # 连接池最大连接数 ) # 创建10个并发查询任务(和你同步代码的循环次数一致) tasks = [test(pool) for _ in range(10)] # 并发执行所有任务 results = await asyncio.gather(*tasks) # 关闭连接池 pool.close() await pool.wait_closed() # Python 3.7+ 推荐用asyncio.run()替代get_event_loop() %timeit asyncio.run(main())
关键改进点说明
- 并发任务提交:用
[test(pool) for _ in range(10)]创建10个异步任务对象,然后通过asyncio.gather(*tasks)让这些任务并发执行,而不是逐个等待,这才是异步IO提速的核心。 - 连接池参数优化:设置
minsize和maxsize,避免每次任务都重新创建连接(连接池本身就是为了复用连接,减少连接开销)。 - 事件循环的现代用法:Python 3.7+ 推荐使用
asyncio.run()来运行异步主函数,不需要手动管理loop对象,代码更简洁易维护。 - 任务结果收集:
asyncio.gather()会返回所有任务的结果列表,你可以根据需要处理这些DataFrame。
额外注意事项
- 如果你的查询结果很大,
pandas.DataFrame.from_records是CPU密集型操作,可能会阻塞事件循环。这种情况下可以考虑用loop.run_in_executor()把DataFrame转换操作放到线程池里执行,避免影响其他异步任务。 - 确保你的MySQL服务器配置支持足够的并发连接数,避免因为连接数不足导致任务阻塞。
内容的提问来源于stack exchange,提问作者dnjs7292
相关产品推荐
相关产品推荐

