4

I have been attempting to run 10 different looping tasks simultaneously with asyncio. All 10 tasks call "asyncio.create_task()" within their loops. I can't use "asyncio.run()" on all of them because this functions blocks the thread its called on until the task is done. So I thought that I could simply circumvent this by calling a function with "asyncio.run()" and then inside that function call my 10 looping functions through "asyncio.create_task()". The 10 looping functions are indeed called, but they themselves cannot use "asyncio.create_task()". Any suggestions on how to fix this issue?

This is a based code I have written to demonstrate my issue:

async def task2(): print("Task 2 was called") async def task1(): print("Task 1 was called") asyncio.create_task(task2()) async def main(): print("Main was called") asyncio.create_task(task1()) asyncio.run(main()) 

It prints:

Main was called Task 1 was called 

Any ideas or suggestions would be appreciated :D

5
  • 1
    if you have blocking tasks, are threads sufficient? otherwise just create every task and asyncio.gather() 'em all Commented Jul 3, 2024 at 0:33
  • I tried calling "asyncio.run()" on each task through a separate thread. The program errored out with "can't register atexit after shutdown". I have no idea where this is coming from as that is the whole error and no line is given (the thread doesn't end, it just keeps printing "can't register atexit after shutdown"). Commented Jul 3, 2024 at 0:52
  • 1
    I tried asyncio.gather() and it seems to work, thank you :D Commented Jul 3, 2024 at 1:16
  • excellent - check this out too, which may be a duplicate asyncio.gather vs asyncio.wait (vs asyncio.TaskGroup) Commented Jul 3, 2024 at 1:47
  • No problem with the task creation in your example, but the created task(s) did not get time to run. DO NOT return from the main() until all work is done. Commented Jul 3, 2024 at 8:02

3 Answers 3

2

You can create all the tasks and then asyncio.gather() them

await asyncio.gather(*[task1(), task2()]) 
Sign up to request clarification or add additional context in comments.

Comments

0

In your case gather may do the trick, but to run asyncio.create_task inside a task is possible. You would have to pass control to the even_loop in order for the scheduled tasks to actually start executing.

As far as I know the only proper way to pass control to the event loop is by calling asyncio.sleep(0) (there is a debate on whether this is the right way, the only way, and how much it sucks).

So in your code:

import asyncio async def task2(): print("Task 2 was called") async def task1(): print("Task 1 was called") second = asyncio.create_task(task2()) await asyncio.sleep(0) print("task 1 again") await second async def main(): print("Main was called") await asyncio.create_task(task1()) asyncio.run(main()) 

The key is that asyncio.create_task(task2()) will create and schedule the task. The task will be executed the next time the event_loop executes a task. Without await asyncio.sleep(0) the task scheduler never gets a chance to run any other tasks.

await second is almost cosmetic, but on a high traffic server, I would asyncio.gather(second, third, fourth) before the end of the function, which will guarantee that the process is not terminated before all the subtasks are done.

Comments

-1

asyncio.create_task() returns a Task object which is an Awaitable.

You should use await asyncio.create_task(task1()) instead of asyncio.create_task(task1())

2 Comments

How would I be able to run the other 9 loop tasks if I am awaiting for the first task to end (meaning I wouldn't be able to run them simultaneously)?
await asyncio.create_task(task1()) makes no sense. It is equal to await task1(), just with more overhead.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.