Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a difference between 'await future' and 'await asyncio.wait_for(future, None)'?

With python 3.5 or later, is there any difference between directly applying await to a future or task, and wrapping it with asyncio.wait_for? The documentation is unclear on when it is appropriate to use wait_for and I'm wondering if it's a vestige of the old generator-based library. The test program below appears to show no difference but that doesn't really prove anything.

import asyncio

async def task_one():
    await asyncio.sleep(0.1)
    return 1

async def task_two():
    await asyncio.sleep(0.1)
    return 2

async def test(loop):
    t1 = loop.create_task(task_one())
    t2 = loop.create_task(task_two())

    print(repr(await t1))
    print(repr(await asyncio.wait_for(t2, None)))

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

main()
like image 332
zwol Avatar asked Sep 13 '17 19:09

zwol


People also ask

What is an Asyncio Future?

Introduction to the Python asyncio future A future is an object that returns a value later in the future but not now. Typically, a future object is the result of an asynchronous operation. For example, you may call an API from a remote server and expect to receive the result later.

What does await do in Asyncio?

The keyword await passes function control back to the event loop. (It suspends the execution of the surrounding coroutine.) If Python encounters an await f() expression in the scope of g() , this is how await tells the event loop, “Suspend execution of g() until whatever I'm waiting on—the result of f() —is returned.

What does Future pending mean in Python?

A Future represents an eventual result of an asynchronous operation. Not thread-safe. Future is an awaitable object. Coroutines can await on Future objects until they either have a result or an exception set, or until they are cancelled.


2 Answers

The wait_for gives two more functionalities:

  1. allow to define timeout,
  2. let you specify the loop

Your example:

await f1
await asyncio.wait_for(f1, None)  # or simply asyncio.wait_for(f1)

besides an overhead of calling additional wrapper (wait_for), they're the same (https://github.com/python/cpython/blob/master/Lib/asyncio/tasks.py#L318).

Both awaits will wait indefinitely for the results (or exception). In this case plain await is more appropriate.

On the other hand if you provide timeout argument it will wait for the results with time constraint. And if it will take more than the timeout it will raise TimeoutError and the future will be cancelled.

async def my_func():
    await asyncio.sleep(10)
    return 'OK'

# will wait 10s 
await my_func()

# will wait only 5 seconds and then will raise TimeoutError
await asyncio.wait_for(my_func(), 5)

Another thing is the loop argument. In the most cases you shouldn't be bothered, the use case is limited: inject different loop for tests, run other loop ...

The problem with this parameter is, that all subsequent tasks/functions should also have that loop passed along...

More info https://github.com/python/asyncio/issues/362

  • Passing asyncio loop by argument or using default asyncio loop

  • Why use explicit loop parameter with aiohttp?

like image 199
kwarunek Avatar answered Oct 04 '22 06:10

kwarunek


Unfortunately the python documentation is a little bit unclear here, but if you have a look into the sources its pretty obvious:

In contrary to await the coroutine asyncio.wait_for() allows to wait only for a limited time until the future/task completes. If it does not complete within this time a concurrent.futures.TimeoutError is raised.

This timeout can be specified as second parameter. In your sample code this timeout parameter is None which results in exactly the same functionality as directly applying await/yield from.

like image 36
mrh1997 Avatar answered Oct 04 '22 05:10

mrh1997