Run Background Tasks with asyncio.create_task in Python

Create background tasks in an asyncio event loop with asyncio.create_task and run them concurrently using asyncio.gather.

Easy Python 3.7+ Aug 9, 2026 Concurrency & performance 13 views 0 copies

Python code

27 lines
Python 3.7+
import asyncio
import time

async def background_worker(name, duration):
    """Simulates a long-running background task."""
    print(f"{name} started at t={time.monotonic():.1f}")
    await asyncio.sleep(duration)
    print(f"{name} finished at t={time.monotonic():.1f}")

async def main():
    print(f"Main starting at t={time.monotonic():.1f}")
    
    # Create background tasks (not awaited immediately)
    task1 = asyncio.create_task(background_worker("Worker A", 3))
    task2 = asyncio.create_task(background_worker("Worker B", 1))
    task3 = asyncio.create_task(background_worker("Worker C", 2))
    
    # This runs immediately while background tasks proceed
    print(f"Main doing something else at t={time.monotonic():.1f}")
    await asyncio.sleep(0.5)
    
    # Wait for all background tasks to complete
    await asyncio.gather(task1, task2, task3)
    print(f"All tasks done at t={time.monotonic():.1f}")

if __name__ == "__main__":
    asyncio.run(main())

Output

stdout
Main starting at t=0.0
Worker A started at t=0.0
Worker B started at t=0.0
Worker C started at t=0.0
Main doing something else at t=0.0
Worker B finished at t=1.0
Worker C finished at t=2.0
Worker A finished at t=3.0
All tasks done at t=3.0

How it works

asyncio.create_task schedules the coroutine to run on the event loop immediately, but it does not block code that follows. The three workers start at nearly the same time because they are asynchronous. await asyncio.sleep(0.5) lets the main coroutine yield control so the workers can proceed. asyncio.gather waits for all tasks to complete before moving on. The event loop runs until asyncio.run(main()) finishes.

Common mistakes

  • Forgetting to await asyncio.gather, causing warnings about never-awaited tasks.
  • Calling the coroutine directly like `background_worker(...)` instead of wrapping with `asyncio.create_task`, which doesn't schedule it.
  • Using `time.sleep` inside async functions, which blocks the event loop instead of `await asyncio.sleep`.

Variations

  1. Use `asyncio.wait` with `return_when=asyncio.FIRST_COMPLETED` to handle tasks as they finish.
  2. Apply `asyncio.TaskGroup` in Python 3.11+ for cleaner error handling.

Real-world use cases

  • Kicking off multiple independent I/O operations, like parallel HTTP requests to different APIs.
  • Running periodic background jobs (e.g., health checks or log rotation) while the main service stays responsive.
  • Preloading data from several databases simultaneously before starting your application logic.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Concurrency & performance

Related tutorials and quizzes for this topic.