I have a little understanding problem with asyncio and aiohttp.
Looking at my code, I would expect the following: Asyncio gather() starts with funk1 first. The "a" is printed and the buy order to the okx crypto exchange is sent. After the await okxprivatsocket.send_str, control is given up and the code jumps to funk2(). The “c” is now printed out. Finally, when await okxprivatsocket.send_str is completed, the "b" is printed.
If I run the code now, I get the following output: a , b, c. And that's exactly what I don't understand. It seems as if "await okxprivatsocket.send_str" waits for the result and only then moves on to funk2. The way I understood asyncio is that control is relinquished after the await keyword. What am I misunderstanding?
I would be very grateful for an explanatory answer, Greetings, Andreas
Here is my code:
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())
await(andasync for/with) are the only places your code may yield to the event loop. This is easily shown with your funk2() function. The code in that function clearly doesn't yield to the event loop, therefore awaiting it will never yield to the event loop:This code will never yield and is functionally the same as a synchronous function.
The reason that send_str() didn't yield may be because the data is small and the socket is open and ready, so it was able to push all the data into the socket buffer without delay and complete without waiting for any IO. I suspect if you sent a larger request or lots of requests over the same socket, you'd find the buffer filling up and then it'd yield to the loop while waiting for the socket to be ready for more data.
If you need to ensure your code is yielding at some point, to make sure it doesn't block for too long, then you can use
await asyncio.sleep(0)which will yield to the event loop for 1 iteration.