I am trying to do a deep dive into Python’s asyncio module. I understand we need to await the coroutine to get their results and when we await any coroutine, the surrounding coroutine cedes its execution to the event loop and lets any other coroutine run which is ready for execution.

Consider the following example:

async def parse_data(idx,pool):
    await compute_and_fetch_data()
    # Do some work


async def compute_and_fetch_data(idx, pool):
    # Do some CPU intensive task such as a complex compuation and produce the query to be executed
    
    #Hardcoding query for demonstration
    query = "SELECT * FROM customers" 
    async with pool.acquire() as conn:
        async with conn.cursor() as cur:
            await cur.execute(query)
            result = await cur.fetchall()
            logger.info(f"Fetched result for query {idx+1} successfully.")
            return result

async def main():
    pool = await aiomysql.create_pool(host='localhost', user='user', password='password', db='laundry')
    asyncio.gather(parse_data(1, pool))

asyncio.run(main())
    

Inside the parse_data coroutine, we are awaiting the compute_and_fetch_data coroutine. I have added a placeholder to represent some computations that compute_and_fetch_data will be doing before executing a query on the database. As computing is a CPU-intensive task and executing a query is an IO-bound task, will the parse_data coroutine cede its execution as soon as it reaches the await compute_and_fetch_data code block or will it do the computations inside the compute_and_fetch_data first and cede the execution when it reaches the stage where it needs to execute the query on the database(a time-consuming process) ?

If the latter is true, is it still valid to say that the surrounding coroutine cedes its execution when it reaches the await keyword?