Wait for asyncio.create_task to get results in Spyder IDE

25 Views Asked by At

I am trying to understand how asynchronous calls run in python using Spyder IDE.

I have written the following code:

import asyncio
from concurrent.futures import ThreadPoolExecutor

async def factorial(number):
    f = 1
    for i in range(2, number + 1):
        await asyncio.sleep(1)
        f *= i
    print(f"Task {number}: factorial({number}) = {f}")
    return f

async def main():
    # Schedule three calls *concurrently*:
    executor = ThreadPoolExecutor(max_workers=10)
    loop = asyncio.get_event_loop()
    L =  [await loop.run_in_executor(executor, factorial, i) for i in range(2,5)]
    L = await asyncio.gather(*L)
        

    print(L)
    return(L)

if __name__ == '__main__':
    a = asyncio.create_task(main())
    if a.done():
        res = a.result()
        print("RESULT:",res)
    print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")

I was hoping to get results from asyncio,create_task but from Spyder´s console a get the folowing results:

In[1] :

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Task 2: factorial(2) = 2

Task 3: factorial(3) = 6

Task 4: factorial(4) = 24

[2, 6, 24]

Looks like print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") is runing before I get the results from asyncio.create_task(), and actually I don´t see the results printed on screen print("RESULT:",res).

What I am missing?

Any help is much appreciated.

1

There are 1 best solutions below

2
Teemu Risikko On

This issue seems to be specific to spyder, where I assume you encountered a problem where asyncio.run() could not be used because of an already existing event loop. Normally you would do this:

res = asyncio.run(main())
print("RESULT:", res)

But since this apparently does not work for spyder, we need other options.

First option

What currently happens with a = asyncio.create_task(main()) is that you are essentially creating a task that you are not awaiting. One option would be to just move all of the code apart from the asyncio.create_task(main()) to main(), that's kind of the point of the function. You are basically already printing the result with print(L), so do you need the other print?

Second option

Like said, normally you would await anything that you create with create_task. Now you are checking the result once and then giving up, which is why the final print executes too early. Since await won't work without being in an async function already, you need something else, maybe a while loop:

if __name__ == '__main__':
    a = asyncio.create_task(main())

    while not a.done():
        asyncio.sleep(1)
    
    res = a.result()
    print("RESULT:",res)

Third option

Third option comes from this answer: https://stackoverflow.com/a/65696398/6845813

You would change the configuration of spyder to run the file in an external terminal, in which case the normal workflow would work:

asyncio.run(main())
print("RESULT":, res)

I thin this option is the best for portability within editors, but that's just my preference.