Недавно я столкнулся с проблемой смешения кода на основе Gevent и Asyncio, потому что некоторые синхронные библиотеки работают очень хорошо, когда я монтирую их патч с gevent.monkey.patch_all()
.Я нашел библиотеку aiogevent
, которая, кажется, помогает в реализации PEP 3156, и заменил цикл событий asyncio другой реализацией по вашему выбору (в данном случае это gevent).Я обнаружил, что последние важные коммиты в репозитории git были сделаны 4 года назад.После исправления setup.py мне удалось успешно установить его, но проблема в том, что он не проходит весь тест.
Одним из таких тестов является test_soon , который порождает гринлет, который должен выполнить операцию и остановить цикл.Этот тест зависает навсегда, потому что loop.stop()
не влияет на цикл, который, как ожидается, остановится, когда все задачи будут завершены.Я написал два фрагмента, чтобы проверить, происходит ли это с традиционными сопрограммами, а другой - с гринлетами через gevent.spawn
.
import gevent
import aiogevent
import asyncio
asyncio.set_event_loop_policy(aiogevent.EventLoopPolicy())
loop = asyncio.get_event_loop()
async def func():
print('bloop')
loop.stop()
loop.create_task(func())
loop.run_forever() # works alright and stops as soon as func finish
И с gevent.spawn
:
import gevent
import aiogevent
import asyncio
asyncio.set_event_loop_policy(aiogevent.EventLoopPolicy())
loop = asyncio.get_event_loop()
def func():
print('bloop')
loop.stop()
g = gevent.spawn(func)
loop.run_forever() # func is executed as soon as loop runs, but loop.stop() is ignored
И вопрос:что здесь может пойти не так?Я ясно вижу, что гринлет запускается после запуска цикла, но он «не отслеживается» циклом?Я не могу найти точную строку в источниках asyncio, которая соответствует этому механизму, и то же самое для gevent - я не совсем знаком с внутренностями этих модулей, и поиск в них сбивает с толку, но я хочу знать, в чем разница ичто нужно изменить в цикле событий aiogevent
, чтобы пройти тесты.
upd1 : чтобы подчеркнуть проблему, gevent.hub.Hub
не имеет "открытых" дескрипторовчтобы остановить цикл, только те, кто должен его полностью уничтожить (gevent.hub.get_hub().destroy()
в настоящее время не имеет никакого эффекта, и попытка присоединиться к хаблету-концентратору не удастся, если не будет вызвана в MAIN-гринлете).У него есть внутреннее исключение, которое возникает где-то при выходе из цикла (gevent.exceptions.LoopExit
).Я хотел найти способ, как перехватить это исключение и связать его с run_forever, но пока безрезультатно.