For I/O bound tasks, python coroutines make a nice replacement for threads. Unfortunately, there’s no asynchronous API for reading files, as discussed in the Best way to read/write files with AsyncIO thread of the python-tulip mailing list.
Meanwhile, it is essential that a long-running coroutine contain some asynchronous calls, since otherwise it will run all the way to completion before any other event loop tasks are allowed to run. For a long-running coroutine that needs to call a conventional iterator (rather than an asynchronous iterator), I’ve found this converter class to be useful:
class AsyncIteratorExecutor: """ Converts a regular iterator into an asynchronous iterator, by executing the iterator in a thread. """ def __init__(self, iterator, loop=None, executor=None): self.__iterator = iterator self.__loop = loop or asyncio.get_event_loop() self.__executor = executor def __aiter__(self): return self async def __anext__(self): value = await self.__loop.run_in_executor( self.__executor, next, self.__iterator, self) if value is self: raise StopAsyncIteration return value
For example, it can be used to asynchronously read lines of a text file as follows:
async def cat_file_async(filename): with open(filename, 'rt') as f: async for line in AsyncIteratorExecutor(f): print(line.rstrip()) if __name__ == '__main__': loop = asyncio.get_event_loop() try: loop.run_until_complete( cat_file_async('/path/of/file.txt')) finally: loop.close()