55
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import time

async def foo():
  await time.sleep(1)

foo()

I couldn't make this dead simple example to run:

RuntimeWarning: coroutine 'foo' was never awaited foo()
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
smilingpoplar
  • 1,065
  • 1
  • 15
  • 26
  • Time.sleep is NOT a coroutine so you can't await this even if you properly run the event loop. Moreover if you use blocking code in the event loop you make it synchronous again. There is no point to do this. – Marek Marczak Aug 30 '19 at 17:38

2 Answers2

78

Running coroutines requires an event loop. Use the asyncio() library to create one:

import asyncio

# Python 3.7+
asyncio.run(foo())

or

# Python 3.6 and older
loop = asyncio.get_event_loop()
loop.run_until_complete(foo())

Also see the Tasks and Coroutines chapter of the asyncio documentation. If you already have a loop running, you'd want to run additional coroutines concurrently by creating a task (asyncio.create_task(...) in Python 3.7+, asyncio.ensure_future(...) in older versions).

Note however that time.sleep() is not an awaitable object. It returns None so you get an exception after 1 second:

>>> asyncio.run(foo())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/.../lib/python3.7/asyncio/runners.py", line 43, in run
    return loop.run_until_complete(main)
  File "/.../lib/python3.7/asyncio/base_events.py", line 573, in run_until_complete
    return future.result()
  File "<stdin>", line 2, in foo
TypeError: object NoneType can't be used in 'await' expression

In this case you should use the asyncio.sleep() coroutine instead:

async def foo():
    await asyncio.sleep(1)

which is cooperates with the loop to enable other tasks to run. For blocking code from third-party libraries that do not have asyncio equivalents, you could run that code in an executor pool. See Running Blocking Code in the asyncio development guide.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • If foo() is function from one library, is it possible to encapsulate (without modify the source code) to meet `await` requirement? – northtree Nov 26 '18 at 23:25
  • 1
    @northtree: You can [run blocking code in a threadpool executor](https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor) to free the asyncio event loop thread though. Just be careful with blocking threads that have no way of cancelling them. – Martijn Pieters Nov 27 '18 at 11:45
3

If you already have a loop running (with some other tasks), you can add new tasks with:

asyncio.ensure_future(foo())

otherwise you might get

The event loop is already running

error.

lenooh
  • 10,364
  • 5
  • 58
  • 49