#Что происходит и как распознать неисправность
RuntimeError: asyncio.run() cannot be called from a running event loop возникает, когда код пытается начать новый цикл asyncio внутри потока, где он уже запущен. Типичные места: Jupyter, асинхронные веб-обработчики, функции async def и тестовые среды.
#Как отличить причины
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| asyncio.run внутри async defФункция уже исполняется внутри цикла и пытается создать второй. | В стеке вызовов есть async def и asyncio.run. | Вызовите корутину через await. |
| Интерактивная среда с собственным цикломJupyter/IPython запускает цикл для выполнения ячеек. | В обычном скрипте код работает, в ячейке — ошибка. | На верхнем уровне ячейки используйте await. |
| Смешение синхронного интерфейса и асинхронногоБиблиотека внутри асинхронного обработчика скрыто вызывает asyncio.run. | Ошибка приходит из адаптера или сторонней функции. | Используйте асинхронный API библиотеки вместо вложенного запуска. |
#Пошаговая диагностика и исправление
- Определите, где именно вызван asyncio.runОткройте traceback в терминале или журнале, найдите последнюю строку вашего файла перед
RuntimeError. В редакторе VS Code нажмите Ctrl+P, откройте указанный файл и найдитеasyncio.run(через Ctrl+F. Если строка находится внутриasync def, переходите сразу к изменению вызова наawait. - Сохраните исходный фрагмент и проверьте контекстСкопируйте работающий файл в отдельную ветку Git либо сохраните его локальную копию. Найдите функцию, где встречается
asyncio.run(...), и её объявление:async defили обычныйdef. Проверьте, вызывает ли библиотека этот код из веб-сервера/бота/Jupyter. Не пытайтесь отключить уже запущенный цикл ради одного вызова. - Замените вложенный запуск внутри async def на awaitКогда внешний код асинхронный, замените
result = asyncio.run(fetch_data())наresult = await fetch_data(). Оставьтеasyncio.run(main())только на уровне запуска автономного скрипта подif __name__ == "__main__". Сохраните и запустите тестовый сценарий. Если после замены возникаетSyntaxError: await outside function, вы редактируете синхронную функцию: пересмотрите границы async API. - В Jupyter используйте существующий циклЕсли ошибка появляется в ячейке Jupyter Notebook/Lab, удалите внешний вызов
asyncio.run(...)и напишите непосредственноawait main()на верхнем уровне ячейки. Запустите ячейку кнопкой Run. Ожидается результат корутины без создания второго цикла. Если среда не поддерживает верхнеуровневый await, проверьте её версию; не копируйте обходные monkey-patch из случайных статей. - Если функцию вызывают синхронные участки, разделите интерфейсСоздайте
async def perform()для асинхронной работы и отдельную синхронную точку входаdef main(): asyncio.run(perform())только для команды запуска. Из уже работающего цикла используйтеawait perform(). Это исключает вложенность; не вызывайте синхронный main из асинхронного обработчика. - Проверьте исключения и незавершённые задачиПовторите прежний сценарий. Если вместо прежней ошибки появилось
coroutine was never awaited, убедитесь, что вызов добавлен сawaitили намеренно запланирован как задача, которую затем ожидают. Если программа зависает, проверьте ожидание ввода/сети с таймаутами в коде, а не создавайте дополнительные event loop. - Верните исходный код, если изменилась логикаПроверьте возвращаемое значение, число выполненных запросов и отсутствие предупреждений. Если исправление нарушило API библиотеки, верните файл из сохранённой копии и подберите её нативный асинхронный метод. Зафиксируйте стек и версии Python/библиотеки.
#Команды и примеры для проверки
await main() в ячейке вместо нижних строк.import asyncio
async def fetch_data():
await asyncio.sleep(0.1)
return "готово"
async def main():
result = await fetch_data()
print(result)
if __name__ == "__main__":
asyncio.run(main())python -V#Как проверить результат и что делать дальше
Ошибка устранена, если тот же сценарий исполняется без RuntimeError и без предупреждения о неисполненной корутине. Внутри работающего event loop не вызывайте asyncio.run, а переключайтесь на await; в обычном самостоятельном скрипте оставляйте один запуск на верхнем уровне.