5

I was trying to explain an example of async programming in python but I failed. Here is my code.

import asyncio import time async def asyncfoo(t): time.sleep(t) print("asyncFoo") loop = asyncio.get_event_loop() loop.run_until_complete(asyncfoo(10)) # I think Here is the problem print("Foo") loop.close() 

My expectation is that I would see:

Foo asyncFoo 

With a wait of 10s before asyncFoo was displayed.

But instead I got nothing for 10s, and then they both displayed.

What am I doing wrong, and how can I explain it?

5
  • youtube.com/watch?v=ZzfHjytDceU might be helpful Commented Dec 22, 2016 at 12:40
  • I don't think it is fair to put this question on hold. He clearly says he wants to "Foo" to be printed before "asyncFoo". Commented Dec 22, 2016 at 13:01
  • FWIW, time.sleep is also blocking. Async is useful for resuming execution while waiting for IO, not blocking the thread. Commented Dec 22, 2016 at 13:01
  • You might wanna use asyncio.sleep(10) instead. Also please note loop.run_until_complete is a blocking one, so you might wanna have two async functions, one for the "slow foo" and one for the "fast foo". I wanted to post a complete answer but unfortunately somebody has put this question on hold. Commented Dec 22, 2016 at 13:06
  • Now it's open. You can explain now. Commented Dec 23, 2016 at 3:45

3 Answers 3

11

run_until_complete will block until asyncfoo is done. Instead, you would need two coroutines executed in the loop. Use asyncio.gather to easily start more than one coroutine with run_until_complete.

Here is a an example:

import asyncio async def async_foo(): print("asyncFoo1") await asyncio.sleep(3) print("asyncFoo2") async def async_bar(): print("asyncBar1") await asyncio.sleep(1) print("asyncBar2") loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.gather(async_foo(), async_bar())) loop.close() 
Sign up to request clarification or add additional context in comments.

Comments

2

Your expectation would work in contexts where you run your coroutine as a Task independent of the flow of the code. Another situation where it would work is if you are running multiple coroutines side-by-side, in which case the event-loop will juggle the code execution from await to await statement.

Within the context of your example, you can achieve your anticipated behaviour by wrapping your coroutine in a Task object, which will continue-on in the background without holding up the remainder of the code in the code-block from whence it is called.

For example.

import asyncio async def asyncfoo(t): await asyncio.sleep(t) print("asyncFoo") async def my_app(t): my_task = asyncio.ensure_future(asyncfoo(t)) print("Foo") await asyncio.wait([my_task]) loop = asyncio.get_event_loop() loop.run_until_complete(my_app(10)) loop.close() 

Note that you should use asyncio.sleep() instead of the time module.

3 Comments

it prints foo but fails to print asyncfoo.
The event loop is exiting before the task completes. One way to keep the event loop open is to use loop.run_forever(), another way is to assign the task to a variable, e.g. my_task_var and then wait for the task to finish using await asyncio.wait(my_task_var). In this case, await the task variable at a location that doesn't block your code execution, e.g. Place it after the print("Foo") statement.
@Scripting.FileSystemObject updated answer with version that now works and exits automatically. (Have been away from a computer for a few weeks...)
-1

run_until_complete is blocking. So, even if it'll happen in 10 seconds, it will wait for it. After it's completed, the other print occurs.

You should launch your loop.run_until_complete(asyncfoo(10)) in a thread or a subprocess if you want the "Foo" to be print before.

2 Comments

I see little gain with more complexity of using async with python. Why can't it be as simple as in node?
Running async and a thread/subprocess misses the point in this example.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.