Angezerus
Angezerus

Reputation: 45

Concurrent Async Function call in Python 3.6

I have a script in which a Slow and a Fast function processes the same global object array. The Slow function is for filling up the array with new objects based on resource intensive calculations, the Fast is only for iterating the existing objects in the array and maintaining/displaying them. The Slow function only needs to be run only in every few seconds, but the Fast function is imperative to run as frequently as possible. I tried using asyncio and ensure_future calling the Slow process, but the result was that the Fast(main) function ran until I stopped it, and only at the end was the Slow function called. I need the Slow function to start running in the instance it is called in the background and complete whenever it can, but without blocking the call of the Fast function. Can you help me please? Thank you!

An example of what I tried:

import asyncio
variable = []

async def slow():
    temp = get_new_objects() #resource intensive
    global variable
    variable = temp

async def main():
    while True: #Looping
        if need_to_run_slow: #Only run sometimes
            asyncio.ensure_future(slow())

        do_fast_stuff_with(variable) #fast part

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
    loop.close()

Upvotes: 0

Views: 277

Answers (1)

user4815162342
user4815162342

Reputation: 154846

asyncio.ensure_future(slow()) only schedules slow() to run at the next pass of the event loop. Since your while loop doesn't await anything that can actually block, you are not giving the event loop a chance to run.

You can work around the issue by adding an await asyncio.sleep(0) after the call to the fast function:

async def main():
    while True:
        if need_to_run_slow:
            asyncio.ensure_future(slow())
        await asyncio.sleep(0)
        do_fast_stuff_with(variable)

The no-op sleep will ensure that at every iteration of the while loop (and between runs of the "fast" function") gives a chance for a previously scheduled slow() to make progress.

However, your slow() doesn't await either, so all of its code will run in a single iteration, which makes the above equivalent to the much simpler:

def main():
    while True:
        slow()  # slow() is an ordinary function
        do_fast_stuff_with(variable)

A code example closer to your actual use case would probably result in a more directly usable answer.

Upvotes: 2

Related Questions