DEV Community

Cover image for Async Python in Production: FastAPI vs Flask for Real-Time Services
alfchee
alfchee

Posted on

Async Python in Production: FastAPI vs Flask for Real-Time Services

Hey Pythonistas! 👋 If you’ve ever tried to build a real-time app with Flask and found yourself tangled in threads, callbacks, or mysterious slowdowns, this article is for you. Today, I want to share the real-world lessons I learned about async programming, concurrency, and why FastAPI is a game-changer for modern, high-performance Python services.

Why Async Matters (and When It Doesn’t)

Let’s be honest: not every app needs async. But if you’re handling lots of simultaneous users, streaming data, or anything that can block (like network calls, file I/O, or waiting for a GPU), async is your best friend. It lets your app do more with less—less hardware, less waiting, less pain.

Flask: The Synchronous Wall

Flask is fantastic for simple APIs and quick prototypes. But when you try to scale up to real-time, concurrent workloads, you hit a wall:

  • Each request blocks a worker: If you’re waiting on a slow database or external API, that worker is stuck.
  • WebSockets are awkward: Flask needs extensions like Flask-SocketIO, which use threads or eventlet/gevent. Debugging and scaling become tricky.
  • No native async/await: You can’t just sprinkle async and await and expect magic.

FastAPI: Async, Await, and a Whole New World

FastAPI is built on Starlette and uses Python’s asyncio under the hood. This means you get:

  • True async endpoints: Use async def and await for non-blocking I/O.
  • WebSockets that scale: Native support, no hacks or monkey-patching.
  • Concurrency that feels natural: Handle hundreds of connections with a single process.

Let’s see the difference in practice.

Example: Handling a Long-Running Task

Flask (synchronous):

from flask import Flask
import time

app = Flask(__name__)

@app.route('/process')
def process():
    time.sleep(5)  # Simulate a blocking task
    return 'Done!'
Enter fullscreen mode Exit fullscreen mode

If 10 users hit /process at once, you need 10 workers. Otherwise, users wait in line.

FastAPI (async):

from fastapi import FastAPI
import asyncio

app = FastAPI()

@app.get('/process')
async def process():
    await asyncio.sleep(5)  # Non-blocking!
    return {'status': 'Done!'}
Enter fullscreen mode Exit fullscreen mode

With async, your app can handle other requests while waiting. One worker, many happy users.

Real-Time WebSockets: The Async Advantage

With Flask-SocketIO, you’re juggling threads or greenlets. With FastAPI:

from fastapi import FastAPI, WebSocket

app = FastAPI()

@app.websocket('/ws')
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    while True:
        data = await websocket.receive_text()
        await websocket.send_text(f"Echo: {data}")
Enter fullscreen mode Exit fullscreen mode

No threads, no magic—just clean, readable async code.

Good Practices for Async Python in Production

  1. Use async def everywhere you can: Especially for endpoints, database calls, and network I/O.
  2. Never block the event loop: Avoid time.sleep(), heavy CPU work, or blocking libraries. Use await asyncio.sleep() or run CPU tasks in a thread pool.
  3. Session Management: Track user sessions with unique IDs. Clean up resources when users disconnect.
  4. Error Handling: Always wrap your async code in try/except blocks. Handle disconnects and unexpected errors gracefully.
  5. Resource Cleanup: Use finally blocks to release resources, close connections, and avoid memory leaks.
  6. Testing Async Code: Use pytest-asyncio or similar tools to write real async tests.

The Payoff: Why It’s Worth It

After switching to FastAPI and async patterns, our real-time service:

  • Handled 3x more users with the same hardware
  • Reduced average response times by 40%
  • Became easier to debug and extend
  • Had fewer production incidents (and happier developers!)

Final Thoughts

Async isn’t just a buzzword—it’s a superpower for modern Python apps. If you’re building real-time, high-concurrency services, FastAPI and async/await will make your life (and your users’ lives) so much better.


This article is based on real-world experience building production async Python services. All code is simplified for clarity but follows best practices.

Top comments (0)