web-dev-qa-db-ja.com

Pythonインタープリターを中断することなく、asyncioイベントループをバックグラウンドで実行できますか?

Asyncioのドキュメントには、「Hello World」を2秒ごとに印刷する方法の2つの例が示されています。 https://docs.python.org/3/library/asyncio-eventloop.html#asyncio-hello-world-callbackhttps://docs.python.org/3/library/asyncio-task.html#asyncio-hello-world-coroutine

インタープリターから実行できますが、実行するとインタープリターにアクセスできなくなります。 asyncioイベントループをバックグラウンドで実行して、インタープリターでコマンドを入力し続けることはできますか?

バックグラウンドスレッド内でイベントループを実行できます。

>>> 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
>>> 
>>> Hello World

mustloopasyncio.set_event_loopを呼び出すことに注意してください。そうしないと、現在のスレッドにイベントループがないというエラーが表示されます。

メインスレッドからイベントループとやり取りしたい場合は、 loop.call_soon_threadsafe 呼び出しに固執する必要があります。

この種のものはインタプリタで実験するのに適切な方法ですが、実際のプログラムでは、スレッドを導入するのではなく、イベントループ内でallコードを実行することをお勧めします。

41
dano

Python 3.8では、新しいasyncio REPLを使用できます。

$ python -m asyncio
>>> async def greet_every_two_seconds():
...     while True:
...         print('Hello World')
...         await from 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())
2
zeronone