Reputation: 43
I am using a third party .Net library in Python 3.6 via Python for .Net which uses EventHandlers to provide asynchronous data to my application, similar to the toy example below:
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
I would like to get this data into an asynchronous generator, something like:
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
Obiviously just throwing asyc
and yield
on the event handler function and await
ing the timer won't do it, but is there a straightforward means of accomplishing this?
Upvotes: 4
Views: 1180
Reputation: 154996
Since the "asynchronous" data comes from another thread, you will need a bridge between asyncio and the thread that invokes tock
. On the asyncio side, you will need to implement an async generator and iterate over it with an async for
loop. For example (untested):
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())
Upvotes: 4