Executing coroutines from call_soon` callback function

I have the following situation:

  • Some inner class (which I don't control) performs my callback function using call_soon .
  • In my callback I would like to name another courotune, but ended up with a β€œfrozen” callback.

I will use a modified Hello World with call_soon () to demonstrate this:

 import asyncio def hello_world(loop): print('Hello') # Call some coroutine. yield from asyncio.sleep(5, loop=loop) print('World') loop.stop() loop = asyncio.get_event_loop() # Schedule a call to hello_world() loop.call_soon(hello_world, loop) # Blocking call interrupted by loop.stop() loop.run_forever() loop.close() 

When I run this, nothing is printed and the program never ends.

Ctrl + C

 Traceback (most recent call last): File "../soon.py", line 15, in <module> loop.run_forever() File "/usr/lib/python3.4/asyncio/base_events.py", line 276, in run_forever self._run_once() File "/usr/lib/python3.4/asyncio/base_events.py", line 1136, in _run_once event_list = self._selector.select(timeout) File "/usr/lib/python3.4/selectors.py", line 432, in select fd_event_list = self._epoll.poll(timeout, max_ev) KeyboardInterrupt 

What is happening and why?

Any correct way to do this?

+7
python python-asyncio
source share
2 answers

The example you mentioned shows how to schedule a callback.

If you use yield from syntax, this function is actually coroutine , and it should be properly formatted:

 @asyncio.coroutine def hello_world(loop): print('Hello') yield from asyncio.sleep(5, loop=loop) print('World') loop.stop() 

Then you can schedule the coroutine as a task using ensure_future :

 loop = asyncio.get_event_loop() coro = hello_world(loop) asyncio.ensure_future(coro) loop.run_forever() loop.close() 

Or, which is the same using run_until_complete :

 loop = asyncio.get_event_loop() coro = hello_world(loop) loop.run_until_complete(coro) 

In two weeks, python 3.5 will be officially released and you can use the new async / await syntax:

 async def hello_world(loop): print('Hello') await asyncio.sleep(5, loop=loop) print('World') 

EDIT . This is a little ugly, but nothing prevents you from creating a callback that plans your coroutine:

 loop = asyncio.get_event_loop() coro = hello_world(loop) callback = lambda: asyncio.ensure_future(coro) loop.call_soon(callback) loop.run_forever() loop.close() 
+7
source share

You can use call_soon to call a coroutine using the following syntax:

 loop.call_soon(asyncio.async, hello_world(loop)) 
0
source share

All Articles