'Python asyncio sleep not wakes up

I am trying yo have a progress indicator where one task is doing something while the other indicates a progress. My hello world version of this things goes to sleep in one of the tasks but never wakes up.

What am I missing?

Thanks a lot

import asyncio
import sys
import time
import itertools


progress = True


def get_progress():
    return progress


async def define_progress():
    print("progress started")
    await asyncio.sleep(2)
    progress = False
    print("progress ended")


async def run_spinner(msg):
    spinner = itertools.cycle(['-', '/', '|', '\\'])
    sys.stdout.write("{0} ".format(msg))
    while(get_progress()):
        sys.stdout.write("{0}".format(next(spinner)))
        sys.stdout.flush()
        time.sleep(0.3)
        sys.stdout.write('\b')


async def main():
    msg = "start logic"
    await asyncio.gather(run_spinner(msg), define_progress())


loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(main())
finally:
    loop.close()

The output looks like below while the second line infinitely run the spinner.

progress started
creating package\



Solution 1:[1]

I had to make progress a global variable and add await asyncio.sleep(1) to run_spinner. I'm not sure this answers your question, but it does seem to do what you wanted.

import asyncio
import sys
import time
import itertools

global progress

progress = True



def get_progress():
    global progress
    return progress

async def define_progress():
    global progress
    print("progress started")
    await asyncio.sleep(2)
    progress = False
    print("progress ended")


async def run_spinner(msg):
    spinner = itertools.cycle(['-', '/', '|', '\\'])
    sys.stdout.write("{0} ".format(msg))
    while(get_progress()):
        sys.stdout.write("{0}".format(next(spinner)))
        sys.stdout.flush()
        time.sleep(0.2)
        sys.stdout.write('\b')
        await asyncio.sleep(1)


async def main():
    msg = "start logic"
    await asyncio.gather(run_spinner(msg), define_progress())


loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(main())
finally:
    loop.close()

Solution 2:[2]

  1. The run_spinner coroutine is missing an await asyncio.sleep(0) to give the other task define_progress some processing time.
  2. The progress = False instruction in the define_progress task creates a local variable which shadows the global variable of the same name. Therefor, even if the define_progress finishes, the run_spinner will continue as it reads the global which is still True.

Remarks: From https://docs.python.org/3.9/library/asyncio-task.html#sleeping

sleep() always suspends the current task, allowing other tasks to run.

Setting the delay to 0 provides an optimized path to allow other tasks to run. This can be used by long-running functions to avoid blocking the event loop for the full duration of the function call.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 REXXman
Solution 2 avans