9
感觉 aiomysql,异步执行多个查询,性能并没有显著的提升啊
source link: https://www.v2ex.com/t/790872
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
代码如下:
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 来说,执行时间并没有显著的提升。各位大佬能指点一下吗?
29 条回复 • 2021-07-21 19:45:01 +08:00
BBCCBB 6 小时 28 分钟前
你这代码逻辑上还是`同步`的, 因为你有 await, 会等待每个 sql 执行完成, 就是说一个 sql 执行完后才会去执行下一步的 sql. 只是你这个 sql 还没执行完的过程中, 线程不会卡在这里,, 而是会去执行其他的异步 task. 等你 await 的 task 返回后再继续执行你这个 task.
异步不是你理解的这样的异步. asyncio 的好处是异步 io 的并发..
异步不是你理解的这样的异步. asyncio 的好处是异步 io 的并发..
ErenJaeger 6 小时 10 分钟前
@BBCCBB 你的意思是 await asyncio.gather()中执行的 sql,还是会顺序执行下去?而不是同时进行查询,查询完毕后返回? 之前写 node.js 的时候,后续处理的步骤都写在回调过程中了,耗时操作不会阻塞,而是去执行下面的步骤了。
ErenJaeger 6 小时 7 分钟前
@chaleaoch await 语法糖的作用应该就是等待异步代码返回结果了吧,类似于回调。我想问的是 asyncio.gather()里面的任务不应该是并发执行的吗
v2exblog 5 小时 30 分钟前
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)
这样试试呢
await asyncio.wait(tasks)
这样试试呢
BBCCBB 5 小时 25 分钟前
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()
类似这两种方式.
nodejs 里, 如果你后续的执行依赖某个 nodejs 异步函数的结果, 那不还是得等异步函数结束拿到结果后再执行后面的结果吗.
1:
var s = asyncFunc(xxx, function (res) {
res 是这个函数的返回值.
}); // 不需要等待 asyncFunc 返回值,
xxx(); //
2:
var res = await asyncFunc(xxx); // 需要等待 asyncFunc 返回值
console.log(res)
xxx()
类似这两种方式.
ErenJaeger 5 小时 1 分钟前
@BBCCBB 是的,这两种方式是写法的区别。 我的意思是:
fuction outside(){
asyncFucn1()
asyncFunc2()
asyncFunc3()
asycnFunc4()
......
}
如果 outside 函数等待里面异步函数结束退出的话,执行时长应该是内部异步函数执行时间最长的时长吧。那我同时发起 N 个 sql 查询,整体查询时长应该是 N 个查询 sql 中执行时长最长的时长吧
fuction outside(){
asyncFucn1()
asyncFunc2()
asyncFunc3()
asycnFunc4()
......
}
如果 outside 函数等待里面异步函数结束退出的话,执行时长应该是内部异步函数执行时间最长的时长吧。那我同时发起 N 个 sql 查询,整体查询时长应该是 N 个查询 sql 中执行时长最长的时长吧
ErenJaeger 4 小时 45 分钟前
@chaleaoch 淦,我调了 1000 次,同步 40 多秒,异步 5 秒多。问题生产环境中一个接口里面不可能会有这么高频次的查询,小频次的查询,同步异步的差距就很不明显
BBCCBB 4 小时 42 分钟前
一个接口不可能这么高, 但是其他的接口也有网络 io, 和你测一个接口 1000 次概念差不多, 并发上去了, asyncio 性能差异就出来了..
如果只是一个接口, 没啥访问, 直接同步搞.. 简单
如果只是一个接口, 没啥访问, 直接同步搞.. 简单
ErenJaeger 4 小时 42 分钟前
@BBCCBB gather 里面是顺序执行的吗?我看官方文档里是这样描述的:
同时运行 aws 序列中的可等待对象。
如果 aws 中的任何 awaitable 是协程,则它会自动安排为任务。
如果所有 awaitable 都成功完成,则结果是返回值的聚合列表。结果值的顺序对应于 aws 中等待的顺序。
如果 return_exceptions 为 False (默认),第一个引发的异常会立即传播到在 gather() 上等待的任务。aws 序列中的其他等待对象不会被取消,而是会继续运行。
如果 return_exceptions 为 True,则将异常视为成功结果,并在结果列表中聚合。
如果 gather() 被取消,所有提交的等待(尚未完成)也将被取消。
如果 aws 序列中的任何 Task 或 Future 被取消,则将其视为引发了 CancelledError - 在这种情况下不会取消 gather() 调用。这是为了防止取消一个提交的任务 /未来导致其他任务 /未来被取消。
同时运行 aws 序列中的可等待对象。
如果 aws 中的任何 awaitable 是协程,则它会自动安排为任务。
如果所有 awaitable 都成功完成,则结果是返回值的聚合列表。结果值的顺序对应于 aws 中等待的顺序。
如果 return_exceptions 为 False (默认),第一个引发的异常会立即传播到在 gather() 上等待的任务。aws 序列中的其他等待对象不会被取消,而是会继续运行。
如果 return_exceptions 为 True,则将异常视为成功结果,并在结果列表中聚合。
如果 gather() 被取消,所有提交的等待(尚未完成)也将被取消。
如果 aws 序列中的任何 Task 或 Future 被取消,则将其视为引发了 CancelledError - 在这种情况下不会取消 gather() 调用。这是为了防止取消一个提交的任务 /未来导致其他任务 /未来被取消。
ErenJaeger 4 小时 37 分钟前
class Pmysql:
def __init__(self):
self.conn = None
self.pool = None
async def initpool(self):
try:
__pool = await aiomysql.create_pool(minsize=10,
maxsize=10,
host=Config.host,
port=Config.port,
user=Config.user,
password=Config.password,
db='db')
return __pool
except Exception as e:
print(e)
print('create connect error.')
async def getCursor(self):
conn = await self.pool.acquire()
cur = await conn.cursor()
return conn, cur
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)
async def getAmysqlobj():
mysqlobj = Pmysql()
pool = await mysqlobj.initpool()
mysqlobj.pool = pool
return mysqlobj
def __init__(self):
self.conn = None
self.pool = None
async def initpool(self):
try:
__pool = await aiomysql.create_pool(minsize=10,
maxsize=10,
host=Config.host,
port=Config.port,
user=Config.user,
password=Config.password,
db='db')
return __pool
except Exception as e:
print(e)
print('create connect error.')
async def getCursor(self):
conn = await self.pool.acquire()
cur = await conn.cursor()
return conn, cur
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)
async def getAmysqlobj():
mysqlobj = Pmysql()
pool = await mysqlobj.initpool()
mysqlobj.pool = pool
return mysqlobj
BBCCBB 4 小时 29 分钟前
gather 不是顺序执行, 都 asyncio 了, 只要里面 task 不阻塞, 就是异步执行的.
你这个没啥问题, 根据你加大到 1000 次, 差距挺大的, 所以应该是量不够大.
你这个没啥问题, 根据你加大到 1000 次, 差距挺大的, 所以应该是量不够大.
BBCCBB 4 小时 12 分钟前
asyncio 不能降低你代码里单个 query 方法的耗时, 他要做的是用少量线程就能支撑超高的并发量,, 这个用线程是很难实现的, 单个请求的响应时间并不会变得更快,
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK