2025, Nov 01 03:17

Phasemap в Jupyter: как исправить RuntimeError с nest_asyncio

Почему phasemap в Jupyter падает с RuntimeError "This event loop is already running" и как решить: используйте nest_asyncio для стабильной работы asyncio.

Запуск минимального примера phasemap в Jupyter может неожиданно завершиться с ошибкой RuntimeError о уже запущенном цикле событий. Сам код корректен; конфликт возникает из‑за того, как внутри используется asyncio. Ниже — короткое объяснение проблемы и практичное решение, которое стабильно работает в ноутбуках.

Как воспроизвести проблему

Ниже приведён минимальный пример, повторяющий официальный туториал, лишь с другими именами. Он вычисляет простую индикаторную функцию на квадратной области и передаёт её в phasemap.run.

import phasemap as ph
def label(pt):
    a, b = pt
    return int(a**2 + b**2 < 1)
result = ph.run(
    label,
    limits=[(-1, 1), (-1, 1)],
    mesh=3,
)

При выполнении в Python 3.11.9 в Jupyter или JupyterLab это может привести к ошибке:

RuntimeError: This event loop is already running

Почему так происходит

phasemap использует asyncio и цикл событий для управления выполнением. В Jupyter свой цикл уже запущен — он обслуживает асинхронность ноутбука. Запустить ещё один цикл в том же потоке нельзя, из‑за чего и появляется RuntimeError. Тот же код, запущенный как обычный скрипт Python (например, через python script.py в терминале), не пересекается с циклом Jupyter и потому работает штатно.

Решение

Самый простой способ подружить phasemap с циклом событий Jupyter — разрешить вложенные циклы. Пакет nest_asyncio патчит уже работающий цикл, чтобы код, запускающий собственные задачи через asyncio, выполнялся без конфликта.

import nest_asyncio
nest_asyncio.apply()
import phasemap as ph
def label(pt):
    a, b = pt
    return int(a**2 + b**2 < 1)
outcome = ph.run(
    label,
    limits=[(-1, 1), (-1, 1)],
    mesh=3,
)
print(outcome)

Достаточно один раз вызвать nest_asyncio.apply() в текущей сессии ядра — после этого код без проблем запускается в Jupyter и ведёт себя так же, как задумано изначально.

Зачем это знать

Среды ноутбуков часто скрывают детали исполнения, на которые опираются библиотеки. Если пакет внутри использует asyncio, уже запущенный в ноутбуке цикл событий проявляет себя только во время выполнения, и сообщение об ошибке может казаться не по теме. Осознание, что такой сценарий в Jupyter типичен, помогает быстро отличить баги в коде от ограничений окружения и применить безопасный обходной путь, не трогая саму библиотеку.

Итоги

Если phasemap.run в Jupyter выдаёт “This event loop is already running”, это конфликт циклов событий, а не проблема алгоритма. Либо запускайте тот же код как обычный Python‑скрипт — там всё работает, либо пропатчьте цикл в ноутбуке с помощью nest_asyncio, чтобы обе части сосуществовали. Такой подход сохраняет плавность рабочего процесса и не меняет исходную логику пакета.

Статья основана на вопросе на StackOverflow от Kieran Cooney и ответе от furas.