8

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.)

3
  • I didn't use asyncio before, but I worked with async programming. the while loop will block the current thread, If you need execute a blocking functions you can use the run_in_executor() method of the EventLoop, this will be run the function in an executor. loop.run_in_executor(executor=None, fn, *args) Commented Sep 29, 2017 at 22:19
  • It is blocked because there is nothing else to do. There is only one task to execute. May be add another task to tasks and the wait would be interleaved Commented Sep 29, 2017 at 22:21
  • 1
    Thanks @balki , it seems like adding another task allowed it to continue, so I'll have to split my run() task into seperate parts. Commented Sep 29, 2017 at 22:36

1 Answer 1

10

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
Sign up to request clarification or add additional context in comments.

4 Comments

This also works, thanks! Now I'll have to decide which correction benefits the program more 3:
Just remember to await on asyncio.sleep() in your background while loop, so other coroutines can be executed too.
Does not use global variable breaks the reason for using asyncio? I can set a global variable inside any loop and stop it without using asyncio. Am I right? Maybe there are any other solutions?
PS: in Python 3.7+ use create_task() instead of ensure_future() docs.python.org/3/library/asyncio-task.html#asyncio.create_task

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.