Python の asyncio で「RuntimeError: Event loop is closed」が解消できない
RuntimeError: Event loop is closed は asyncio のイベントループを閉じた後にコルーチンやコールバックが実行されようとした際に発生します。asyncio.run() に任せ、Windows では WindowsSelectorEventLoopPolicy に切り替えるのが定番の対処です。
公開: 更新:
要約
RuntimeError: Event loop is closed は asyncio のイベントループを閉じた後にコルーチンやコールバックが走ろうとした際の例外です。
多くは Windows + aiohttp の組み合わせ、もしくは loop.close() を自前で呼んだケースで再現します。asyncio.run() に任せ、Windows では WindowsSelectorEventLoopPolicy に切り替えるのが定番の対処です。
よくある原因
- Windows + Python 3.8 以降のデフォルト ProactorEventLoop と aiohttp の SSL クローズ処理の組み合わせ
asyncio.run()の後にさらにloop.close()を呼んでいる- プログラム終了直前に SSL transport などのファイナライザがクローズ済みループへ await する
- Jupyter Notebook 内で
asyncio.run()を呼び、既存ループと衝突している
解決策
1. Windows ではセレクタ系ポリシーに切り替える
aiohttp の README にも記載のある既知の回避策です。asyncio.run() を呼ぶ前に一度だけポリシーを設定します(公式ドキュメント(新しいタブで開く))。
import asyncio
import sys
if sys.platform == "win32":
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
asyncio.run(main())2. ループを自前で閉じない
loop = asyncio.new_event_loop()
loop.run_until_complete(main())
loop.close()
asyncio.run(other())上の書き方は asyncio.run が新しいループを作るタイミングで閉じ忘れの transport を踏みます。
代わりに asyncio.run だけに統一します。
asyncio.run(main())
asyncio.run(other())3. 残タスクを掃除してから終了する
async def main():
await do_work()
pending = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]
for t in pending:
t.cancel()
await asyncio.gather(*pending, return_exceptions=True)
asyncio.run(main())4. Jupyter / IPython では asyncio.run を使わない
Jupyter のセルでは既にイベントループが回っているため、asyncio.run() は失敗します。
トップレベルで await main() と書くか、どうしても asyncio.run() を使いたければ nest_asyncio.apply() で入れ子を許可します。
実行例
実際に上記のコードを python:3.12 環境で動かすと、閉じたループへの run_until_complete 呼び出しが RuntimeError: Event loop is closed を送出して終了コード 1 で終了し、asyncio.run() に統一することで 2 回目も正常に完了(終了コード 0)することが確認できる。
$ python --version
Python 3.12.13$ python bad.py
1回目: done
2回目(閉じたループを再利用):
Traceback (most recent call last):
File "/tmp/tmp.y2ZCN04DZc/bad.py", line 12, in <module>
print(loop.run_until_complete(work()))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/asyncio/base_events.py", line 666, in run_until_complete
self._check_closed()
File "/usr/local/lib/python3.12/asyncio/base_events.py", line 545, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
sys:1: RuntimeWarning: coroutine 'work' was never awaited
終了コード: 1$ python good.py
1回目: done
2回目: done
終了コード: 0— 2026-08-02 時点の出力