SIGNALW

Submit an arbitrary number of coroutines in asyncio event loop during runtime

Asyncio

Python package asyncio allows the script to be executed concurrently. This package is suitable for IO-bound network code, e.g., elimating the busy waiting part when making an API request.

Problem

As I adopt asyncio-related packages in some projects, a need occurred that an arbitrary number of coroutines should be executed during runtime. The coroutine will be called inside an infinite loop when certain condition is met.

Solution

By looking through the documentations, it is not easy to achieve that logic by using ascynio package itself. You can schedule some random coroutines before the program is run, but I do not find a way to add them during runtime.

What I ended up with is to explicitly submit coroutines to a separate thread where the event loop is running, by calling run_coroutine_threadsafe method.

Below is the sample code for reference:

class AsyncLoopThread(Thread):
    """loop wrapper that runs in a separate thread"""
    def __init__(self):
        super().__init__(daemon=True)
        self.loop = asyncio.new_event_loop()

    def run(self):
        asyncio.set_event_loop(self.loop)
        self.loop.run_forever()

async def coroutine(num, sec):
    """example coroutine"""
    await asyncio.sleep(sec)
    print('Coro %d has finished' % num)

if __name__ == '__main__':
    # start a loop in another thread
    loop_handler = AsyncLoopThread()
    loop_handler.start()

    while True:
        # adding first 1000 coros
        for i in range(1000):
            print('Add Coro %d to the loop' % i)
            asyncio.run_coroutine_threadsafe(coroutine(i, randint(3, 5)), loop_handler.loop)

        time.sleep(3)
        print('Adding 1000 more coros')

        # adding 1000 more coros
        for i in range(1000, 2000):
            print('Add Coro %d to the loop' % i)
            asyncio.run_coroutine_threadsafe(coroutine(i, randint(3, 5)), loop_handler.loop)