感觉 aiomysql,异步执行多个查询,性能并没有显著的提升啊

2021-07-21 16:12:06 +08:00
 ErenJaeger

代码如下:

 async def query(self, query, param=None):
        conn, cur = await self.getCursor()
        try:
            await cur.execute(query, param)
            return await cur.fetchall()
        except:
            print('error')
        finally:
            if cur:
                await cur.close()
            await self.pool.release(conn)

# mysqlobj 是 aiomysql 连接池对象

result = await asyncio.gather(mysqlobj.query(sql1), mysqlobj.query(sql2), mysqlobj.query(sql3), mysqlobj.query(sql4), mysqlobj.query(sql5))

在我的理解中,如果异步执行的话,这段代码执行的时长应该是这 5 个 sql 中耗时最长的时长,但是测试多次,相对同步执行这 5 个 sql 来说,执行时间并没有显著的提升。各位大佬能指点一下吗?

4168 次点击
所在节点    Python
40 条回复
BBCCBB
2021-07-21 16:29:32 +08:00
你这代码逻辑上还是`同步`的, 因为你有 await, 会等待每个 sql 执行完成, 就是说一个 sql 执行完后才会去执行下一步的 sql. 只是你这个 sql 还没执行完的过程中, 线程不会卡在这里,, 而是会去执行其他的异步 task. 等你 await 的 task 返回后再继续执行你这个 task.

异步不是你理解的这样的异步. asyncio 的好处是异步 io 的并发..
chaleaoch
2021-07-21 16:36:53 +08:00
同一个 async 中的 await 是顺序执行的要不然不乱套了吗?
ErenJaeger
2021-07-21 16:47:32 +08:00
@BBCCBB 你的意思是 await asyncio.gather()中执行的 sql,还是会顺序执行下去?而不是同时进行查询,查询完毕后返回? 之前写 node.js 的时候,后续处理的步骤都写在回调过程中了,耗时操作不会阻塞,而是去执行下面的步骤了。
ErenJaeger
2021-07-21 16:50:37 +08:00
@chaleaoch await 语法糖的作用应该就是等待异步代码返回结果了吧,类似于回调。我想问的是 asyncio.gather()里面的任务不应该是并发执行的吗
chaleaoch
2021-07-21 17:23:41 +08:00
@ErenJaeger 是并发的没错, 但是 是 task 并发.
协程的基础是生成器 - - 如果从生成器开始看的话 应该会有更好的理解- -
chaleaoch
2021-07-21 17:26:32 +08:00
如图
是 task1 和 task2 之间 切换 和其他的 await 没关系

我手画的 - - 偷懒没画全 希望我表达清楚了
https://cdn.jsdelivr.net/gh/chaleaoch/CDN@main/images/1626859549049-1626859549045.png
joApioVVx4M4X6Rf
2021-07-21 17:27:51 +08:00
tasks = [asyncio.create_task(mysqlobj.query(sql1)),asyncio.create_task(mysqlobj.query(sql2)),asyncio.create_task(mysqlobj.query(sql3)),asyncio.create_task(mysqlobj.query(sql4)),asyncio.create_task(mysqlobj.query(sql5))]

await asyncio.wait(tasks)
这样试试呢
BBCCBB
2021-07-21 17:32:55 +08:00
nodejs 继续执行后面是因为你不用 await nodejs 的这个 promise, 而是等他返回结果返回后, 调用你注册的回调 function.去处理 function 果返回

nodejs 里, 如果你后续的执行依赖某个 nodejs 异步函数的结果, 那不还是得等异步函数结束拿到结果后再执行后面的结果吗.


1:
var s = asyncFunc(xxx, function (res) {
res 是这个函数的返回值.
}); // 不需要等待 asyncFunc 返回值,

xxx(); //


2:
var res = await asyncFunc(xxx); // 需要等待 asyncFunc 返回值
console.log(res)
xxx()

类似这两种方式.
pabupa
2021-07-21 17:40:40 +08:00
楼主这种用法没有问题。
pabupa
2021-07-21 17:41:05 +08:00
pabupa
2021-07-21 17:42:02 +08:00
我觉得应该是驱动的问题,,,
pabupa
2021-07-21 17:42:43 +08:00
@pabupa 比如你的连接池中的连接可能太小了……
ErenJaeger
2021-07-21 17:49:06 +08:00
@chaleaoch 是呀,就是我指的就是 gather 里面的任务并发执行的话,执行时长应该是这里面最长执行任务的时长,而不是所有任务执行时长的累积
Vegetable
2021-07-21 17:52:23 +08:00
用法没问题,不过信息还是不够。包括链接池大小和具体时常。甚至说,mysql 的性能是不是瓶颈,都需要考虑。
ErenJaeger
2021-07-21 17:56:42 +08:00
@BBCCBB 是的,这两种方式是写法的区别。 我的意思是:
fuction outside(){
asyncFucn1()
asyncFunc2()
asyncFunc3()
asycnFunc4()
......
}
如果 outside 函数等待里面异步函数结束退出的话,执行时长应该是内部异步函数执行时间最长的时长吧。那我同时发起 N 个 sql 查询,整体查询时长应该是 N 个查询 sql 中执行时长最长的时长吧
ErenJaeger
2021-07-21 17:57:45 +08:00
@pabupa mix 是 5,max 是 10,按理说应该够了,我调整一下试试
ErenJaeger
2021-07-21 17:58:30 +08:00
@v2exblog 试了试,差不多,timeit 测试了下跟同步查询的差不多,就感觉很奇怪
chaleaoch
2021-07-21 18:00:01 +08:00
@ErenJaeger 换成 100 次查询试一下.
BBCCBB
2021-07-21 18:09:49 +08:00
sorry, 理解错了.. 光看了你问题里写的 5 个 sql, 我漏看了下面的 gather, 你要问的是 gather 里的这 5 个 task 吧
BBCCBB
2021-07-21 18:10:31 +08:00
刚好你这个 task 里也是 5 个 sql 的 await.. :(

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/790872

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX