Why is coroutine 'hello_world' not awaiting correctly?

Viewed 48

This is an adapted version of 'hello world' from the Python docs. It works as expected.

"""hello_world.py"""
import asyncio


async def hello_world():
    print('Hello', end=' ')
    await asyncio.sleep(1)
    print('world.')
    

async def coro_runner(func):
    await func()

asyncio.run(coro_runner(hello_world))

I want to leave the asyncio environment, work with regular functions (i.e. not coroutines) and then return to the asyncio environment. To this end I wrote a new 'hello world'.

The await statement isn't working as expected. It does not return control to the coroutine. The program terminates prematurely without sleeping for a year.

Why?

"""so_bad_hw.py"""
import asyncio
from typing import Callable


async def hello_world():
    print('Hello', end=' ')
    await asyncio.sleep(31_536_000)  # 1 Year
    print('world.')
    
    
async def func_runner(func: Callable):
    await asyncio.sleep(0)
    func()  # Calls not_a_coroutine

    
async def coro_runner(func: Callable):
    await func()  # Calls hello_world

    
def not_a_coroutine():
    loop = asyncio.get_running_loop()
    loop.create_task(coro_runner(hello_world))


asyncio.run(func_runner(not_a_coroutine))

This is the output:

so_bad_hw.py 
Hello 
Process finished with exit code 0
1 Answers

This solution was made possible by @dirn's helpful diagnosis.

"""so_hello_world.py"""
import asyncio
from typing import Callable

background_tasks: set[asyncio.Task] = set()
end_program: asyncio.Event = asyncio.Event()


async def hello_world():
    global end_program
    print('Hello', end=' ')
    await asyncio.sleep(1)
    print('world.')
    end_program.set()

    
def not_a_coroutine():
    task = asyncio.create_task(hello_world())
    background_tasks.add(task)
    task.add_done_callback(background_tasks.discard)


async def main(func: Callable):
    func()
    await end_program.wait()


asyncio.run(main(not_a_coroutine))


Related