Jeffrey Benjamin Brown
Jeffrey Benjamin Brown

Reputation: 3709

Can an asyncio event loop run in the background without suspending the Python interpreter?

The documentation for asyncio gives two examples for how to print "Hello World" every two seconds: https://docs.python.org/3/library/asyncio-eventloop.html#asyncio-hello-world-callback https://docs.python.org/3/library/asyncio-task.html#asyncio-hello-world-coroutine

I can run those from the interpreter, but if I do I lose access to the interpreter. Can an asyncio event loop be run in the background, so that I can keep typing commands at the interpreter?

Upvotes: 46

Views: 84541

Answers (3)

dano
dano

Reputation: 94891

Edit:

If using Python 3.8 or above, you should use the asyncio repl, as explained in zeronone's answer. If using 3.7 or lower, you can use this answer.


You can run the event loop inside a background thread:

import asyncio

@asyncio.coroutine
def greet_every_two_seconds():
    while True:
        print('Hello World')
        yield from asyncio.sleep(2)

def loop_in_thread(loop):
    asyncio.set_event_loop(loop)
    loop.run_until_complete(greet_every_two_seconds())


loop = asyncio.get_event_loop()
import threading
t = threading.Thread(target=loop_in_thread, args=(loop,))
t.start()

# Hello World
# 2 second later
# Hello World

Note that you must call asyncio.set_event_loop on the loop, otherwise you'll get an error saying that the current thread doesn't have an event loop.

If you want to interact with the event loop from the main thread, you'll need to stick to loop.call_soon_threadsafe calls.

While this kind of thing is an ok way to experiment in the interpreter, in actual programs, you'll probably want all your code running inside the event loop, rather than introducing threads.

Upvotes: 68

Yves Surrel
Yves Surrel

Reputation: 303

@raisyn

From ipython, this is working:

import asyncio
from traitlets.config.application import Application

async def greet_every_two_seconds():
    while True:
        print('Hello World')
        await asyncio.sleep(2)
        
# Create coroutine
coro = greet_every_two_seconds()

# Create and get an adequate asyncio event loop
Application.instance().shell.enable_gui('asyncio')
loop = asyncio.get_event_loop()

loop.create_task(coro)

Upvotes: 0

zeronone
zeronone

Reputation: 3041

With Python 3.8, you can use the new asyncio REPL.

$ python -m asyncio
>>> async def greet_every_two_seconds():
...     while True:
...         print('Hello World')
...         await asyncio.sleep(2)
...
>>> # run in main thread (Ctrl+C to cancel)
>>> await greet_every_two_seconds()
...
>>> # run in background
>>> asyncio.create_task(greet_every_two_seconds())

Upvotes: 48

Related Questions