我对 asyncio 和 aiohttp 有一点理解问题。
看看我的代码,我期望得到以下结果:Asyncio Gather() 首先从 funk1 开始。打印“a”并将购买订单发送到 okx 加密货币交易所。在await okxprivatsocket.send_str之后,控制权被放弃,代码跳转到funk2()。现在“c”已打印出来。最后,当await okxprivatsocket.send_str完成时,将打印“b”。
如果我现在运行代码,我会得到以下输出:a、b、c。这正是我不明白的地方。看起来好像“await okxprivatsocket.send_str”等待结果,然后才转到 funk2。我理解asyncio的方式是在await关键字之后放弃控制。我有什么误解吗?
我将非常感谢您的解释性答案, 问候,安德烈亚斯
这是我的代码:
import time
import aiohttp
import asyncio
import okx.websocket.WsUtils as wub
async def main():
apiKey = "XXXXXXXXXXXX"
passphrase = "XXXXXXXXXXX"
secretKey = "XXXXXXXXXXXXXXXXXX"
okxprivat_url = "wss://wsaws.okx.com:8443/ws/v5/private"
loginparamstr = wub.initLoginParams(time.time, apiKey, passphrase, secretKey)
okxprivat_message = '{"op":"subscribe","args":[{"channel":"orders","instType":"SPOT","instId":"KDA-USDT"}]}'
session = aiohttp.ClientSession()
async with session.ws_connect(okxprivat_url) as okxprivatsocket :
await okxprivatsocket.send_str(loginparamstr)
await asyncio.sleep(1)
await okxprivatsocket.send_str(okxprivat_message)
await asyncio.gather(funk1(okxprivatsocket),funk2())
async def funk1(okxprivatsocket):
print("a")
await okxprivatsocket.send_str('{"id":"33321","op": "order","args":[{"side": "buy","instId": "KDA- USDT","tdMode": "cash","ordType": "limit","px": 1, "sz": 10}]}')
print("b")
async def funk2():
print("c")
if __name__ == '__main__':
asyncio.run(main())
我理解asyncio的方式是在await关键字之后放弃控制。我有什么误解吗?
await
(和async for/with
)是您的代码可能屈服于事件循环的唯一地方。这可以通过 funk2() 函数轻松显示。该函数中的代码显然不会屈服于事件循环,因此等待它永远不会屈服于事件循环:
await funk2()
await funk2()
await funk2()
此代码永远不会产生结果,并且在功能上与同步函数相同。
send_str()没有yield的原因可能是因为数据很小,并且套接字已打开并准备就绪,因此它能够将所有数据无延迟地推送到套接字缓冲区并完成,而无需等待任何IO。我怀疑如果您通过同一个套接字发送较大的请求或大量请求,您会发现缓冲区已满,然后在等待套接字准备好接收更多数据时会进入循环。
如果您需要确保代码在某个时刻屈服,以确保它不会阻塞太长时间,那么您可以使用
await asyncio.sleep(0)
,这将屈服于事件循环进行 1 次迭代。