Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python async function inside an async function

My code:

import asyncio
from random import randrange

async def inner_sleep(letter, num):
    print(f'start inner sleep {letter}, {num}')
    myint = randrange(5)
    await asyncio.sleep(myint)
    print(f'done with inner sleep {letter}, {num}')

async def outer_sleep(letter):
    print(f'start outer sleep {letter}')
    myint = randrange(5)
    await asyncio.sleep(myint)
    print(f'done with outer sleep {letter}')

async def inside(letter):
    nums = [1,2,3,4,5,6]
    tasks = []

    async def create_task(num):
        task = asyncio.ensure_future(inner_sleep(letter, num))
        tasks.append(task)
    
    for num in nums:
        await create_task(num)

    await asyncio.gather(*tasks)


async def outside():

    letters = ['a','b','c','d']
    tasks = []

    async def create_task_1(letter):
        task = asyncio.ensure_future(outer_sleep(letter))
        tasks.append(task)

    for letter in letters:
        await create_task_1(letter)
        await inside(letter)
    
    await asyncio.gather(*tasks)

asyncio.run(outside())

Sample output:

start outer sleep a
start inner sleep a, 1
start inner sleep a, 2
start inner sleep a, 3
start inner sleep a, 4
start inner sleep a, 5
start inner sleep a, 6
done with inner sleep a, 4
done with outer sleep a
done with inner sleep a, 2
done with inner sleep a, 3
done with inner sleep a, 1
done with inner sleep a, 5
done with inner sleep a, 6
start outer sleep b
start inner sleep b, 1
start inner sleep b, 2
start inner sleep b, 3
start inner sleep b, 4
start inner sleep b, 5
start inner sleep b, 6
done with inner sleep b, 3
done with inner sleep b, 5
done with inner sleep b, 4
done with outer sleep b
done with inner sleep b, 1
done with inner sleep b, 6
done with inner sleep b, 2
start outer sleep c
start inner sleep c, 1

I have a loop inside a loop and I want both of them to run asynchronously. The inner one works correctly, but I'm having trouble getting the outer one to do what I want. In the code above, I want my outer function to concurrently loop through the list 'letters'. For each letter, I need the first function (outer_sleep) to finish before the second function (inner_sleep) can start. I can't seem to find a place to put the inside function to accomplish this. When I run this code, you can see in the results how 'inner sleep a' starts before 'done with outer sleep a'. Ideally my output would look something like:

start outer sleep a
start outer sleep b
finish outer sleep a
start inner sleep a, 1
start inner sleep a, 2
start inner sleep a, 3
start inner sleep a, 4
start inner sleep a, 5
start inner sleep a, 6
finish outer sleep b
start inner sleep b, 1
start inner sleep b, 2
start inner sleep b, 3
start inner sleep b, 4
start inner sleep b, 5
start inner sleep b, 6
done with inner sleep a, 4
done with inner sleep a, 2
done with inner sleep b, 3

Is this possible?


1 Answers

What about just placing await inside(letter) at the end of outer_sleep? This ensures it will only be run once the result of that specific outer_sleep has arrived.

import asyncio
from random import randrange


async def inner_sleep(letter, num):
    print(f'start inner sleep {letter}, {num}')
    myint = randrange(5)
    await asyncio.sleep(myint)
    print(f'done with inner sleep {letter}, {num}')


async def inside(letter):
    nums = [1, 2, 3, 4, 5, 6]
    tasks = [asyncio.ensure_future(inner_sleep(letter, num)) for num in nums]
    await asyncio.gather(*tasks)


async def outer_sleep(letter):
    print(f'start outer sleep {letter}')
    myint = randrange(5)
    await asyncio.sleep(myint)
    print(f'done with outer sleep {letter}')
    await inside(letter)


async def outside():
    letters = ['a', 'b', 'c', 'd']
    tasks = [asyncio.ensure_future(outer_sleep(letter)) for letter in letters]
    await asyncio.gather(*tasks)


asyncio.run(outside())

The asyncio.gather means that both the numbers as well as the letters can be processed in any order (e.g. 'c' can come before 'b'), if that's okay with you.

like image 57
xjcl Avatar answered Jul 16 '26 04:07

xjcl