Как загрузить асинхронный генератор событиями из python.net

#python #.net #asynchronous #python-asyncio #python.net

#python #.net #асинхронный #python-asyncio #python.net

Вопрос:

Я использую стороннюю программу.Библиотека Net в Python 3.6 через Python для .Net, который использует обработчики событий для предоставления асинхронных данных моему приложению, аналогично приведенному ниже игрушечному примеру:

 import clr
from System import Timers

def tock(__, args):
    print(args.SignalTime)

timer = Timers.Timer()
timer.Interval = 1000
timer.Elapsed  = tock
timer.Enabled = True
while True:
    pass
  

Я хотел бы передать эти данные в асинхронный генератор, что-то вроде:

 import clr
from System import Timers

async def tock(__, args):
    yield args.SignalTime

async def main():
    result = await tock
    print(result)

timer = Timers.Timer()
timer.Interval = 1000
timer.Elapsed  = tock
timer.Enabled = True
while true:
    result = await timer
    print result
  

Очевидно, что простое включение asyc и yield в функцию обработчика событий и await включение таймера этого не сделают, но есть ли простой способ добиться этого?

Ответ №1:

Поскольку «асинхронные» данные поступают из другого потока, вам понадобится мост между asyncio и потоком, который вызывает tock . На стороне asyncio вам нужно будет реализовать асинхронный генератор и выполнить итерацию по нему с помощью async for цикла. Например (непроверенный):

 import clr, asyncio
from System import Timers

def adapt_sync_to_async():
    # Adapt a series of sync callback invocations to an async
    # iterator. Returns an async iterator and a feed callback
    # such that the async iterator will produce a new item
    # whenever the feed callback is fed one.
    loop = asyncio.get_event_loop()
    queue = asyncio.Queue()
    def feed(item):
        loop.call_soon_threadsafe(queue.put_nowait, item)
    async def drain():
        while True:
            yield await queue.get()
    return drain, feed

tock, feed_tock = adapt_sync_to_async()

async def main():
    async for result in tock():
        print(result)

timer = Timers.Timer()
timer.Interval = 1000
timer.Elapsed  = lambda _, args: feed_tock(args.SignalTime)
timer.Enabled = True

asyncio.get_event_loop().run_until_complete(main())
  

Комментарии:

1. Спасибо, это решение работает (после добавления import asyncio , которое я забыл изначально)