Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

While loop blocks asyncio tasks

I've been using asyncio for a bit but I'm still fairly unfamiliar with it. My current issue is that while trying to wait for a response from a function with asyncio, the waiting (while loop) blocks the function from happening. Here is the code that sums up the problem:

import asyncio

response = 0

async def handle(x):
    await asyncio.sleep(0.1)
    return x

async def run():
    global response
    for number in range(1, 21):
        response = await handle(number)
        print(response)
        if response == 10:
            await wait_for_next(response)

async def wait_for_next(x):
    while response == x:
        print('waiting',response,x)
        await asyncio.sleep(0.5)
    print('done')

tasks = [run()]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

wait_for_next is supposed to wait for the next response, but the while loop blocks the run() function. How could I stop this happening? Should I be using loop.run_in_executor, and if so, how?

(There were a couple of other examples of this I could find, but they were very specific and I didn't understand if our problems/solutions would be the same.)

like image 235
ShuckleShackle Avatar asked Sep 29 '17 22:09

ShuckleShackle


1 Answers

As already noted, loop stuck because await wait_for_next(response) blocks execution flow until this coroutine wouldn't be finished.

If you want some of your coroutines to be started without blocking execution flow you can start it as asyncio.Task (more about tasks) using ensure_future function:

import asyncio

response = 0

async def handle(x):
    await asyncio.sleep(0.1)
    return x

async def run():
    global response
    for number in range(1, 21):
        response = await handle(number)
        print(response)
        if response == 10:

            # run wait_for_next "in background" instead of blocking flow:
            asyncio.ensure_future(wait_for_next(response))

async def wait_for_next(x):
    while response == x:
        print('waiting',response,x)
        await asyncio.sleep(0.5)
    print('done')


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(run())

Output:

1
2
3
4
5
6
7
8
9
10
waiting 10 10
11
12
13
14
done
15
16
17
18
19
20
like image 93
Mikhail Gerasimov Avatar answered Sep 22 '22 15:09

Mikhail Gerasimov