Цикл событий aiogevent "не удается" отследить гринлеты - PullRequest
10 голосов
/ 24 июня 2019

Недавно я столкнулся с проблемой смешения кода на основе 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, но пока безрезультатно.

...