# Django Async Views und ASGI 2026: Performance und Interview-Fragen > Ein Deep Dive zu Django Async Views und ASGI 2026: wie sie intern funktionieren, welcher Server zu deployen ist, das Async-ORM und die SynchronousOnlyOperation-Falle sowie Interview-Fragen. - Published: 2026-07-03 - Updated: 2026-07-07 - Author: SharpSkill - Tags: django, async, asgi, python, performance - Reading time: 10 min --- Django Async Views ermöglichen es einem einzelnen Worker, Hunderte gleichzeitiger I/O-gebundener Anfragen zu bedienen, ohne jeder Verbindung einen eigenen Thread zuzuweisen – allerdings nur, wenn der Code-Pfad von der View bis hinunter zu jedem Netzwerkaufruf durchgehend asynchron bleibt. Seit Django 3.1 `async def`-Views eingeführt und Django 4.1 die asynchrone ORM-Schnittstelle ergänzt hat, ist das Framework zu einer ernstzunehmenden ASGI-Plattform geworden. Dennoch laufen die meisten Produktionsdeployments weiterhin unter WSGI und lassen diese Nebenläufigkeit ungenutzt. Dieser Deep Dive erklärt, wie sich Async Views unter ASGI verhalten, welche Server 2026 zum Einsatz kommen, welche ORM-Fallen `SynchronousOnlyOperation` auslösen und welche Interview-Fragen jene Entwickler, die async Django bereits produktiv ausgeliefert haben, von denen unterscheiden, die nur darüber gelesen haben. > **Wann Async wirklich hilft** > > Async Views zahlen sich aus, wenn eine Anfrage die meiste Zeit mit Warten auf I/O verbringt, das sie nicht selbst kontrolliert: Drittanbieter-HTTP-APIs, langsame nachgelagerte Dienste oder langlebige Streaming-Antworten. Für CPU-gebundene Arbeit oder schnelle lokale Datenbankabfragen ist eine synchrone View mit mehr Gunicorn-Workern in der Regel schneller und deutlich einfacher nachzuvollziehen. ## Wie Django Async Views unter ASGI funktionieren WSGI ist grundlegend synchron: Jede laufende Anfrage belegt von Anfang bis Ende einen Worker-Thread oder -Prozess, sodass 50 langsame Anfragen 50 Worker benötigen. ASGI ersetzt dieses Modell durch einen Event Loop, der viele Anfragen auf einem einzigen Worker verschränkt: Eine Coroutine wird ausgesetzt, sobald sie auf I/O wartet, und fortgesetzt, wenn die Daten eintreffen. Die [offizielle Django-Async-Dokumentation](https://docs.djangoproject.com/en/5.2/topics/async/) beschreibt die beiden Adapter, die diese Koexistenz ermöglichen: Unter ASGI führt Django `async def`-Views nativ auf dem Loop aus und schiebt synchrone Views mit `sync_to_async` in einen Threadpool; unter WSGI umschließt es Async Views mit `async_to_sync` und führt sie vollständig aus, wodurch jeglicher Nebenläufigkeitsvorteil verloren geht. Die praktische Konsequenz ist unmissverständlich: Eine `async def`-View, die auf einem WSGI-Server läuft, verhält sich wie eine langsamere synchrone View. Nebenläufigkeit entsteht erst auf einem ASGI-Server. Eine minimale Async View, die eine externe API aufruft, sieht ihrem synchronen Gegenstück fast identisch – der Unterschied konzentriert sich auf das `await`. ```python # views.py import httpx from django.http import JsonResponse async def dashboard(request): # Unter ASGI läuft diese Coroutine auf dem Event Loop, sodass der Worker # andere Anfragen bedienen kann, während httpx auf den Netzwerk-Roundtrip wartet. async with httpx.AsyncClient(timeout=5.0) as client: response = await client.get("https://api.example.com/metrics") return JsonResponse(response.json()) ``` Der Gewinn besteht hier nicht darin, dass die einzelne Anfrage schneller abschließt; sie benötigt dieselbe Wall-Clock-Zeit. Der Gewinn besteht darin, dass der Worker während des `await` nicht blockiert wird, sodass der Durchsatz unter gleichzeitiger Last steigt, während die Prozessanzahl konstant bleibt. Dasselbe Modell erschließt Antwortmuster, die unter WSGI umständlich sind. Seit Django 4.2 akzeptiert `StreamingHttpResponse` einen asynchronen Generator, sodass eine View Chunks ausliefern kann, sobald eine vorgelagerte Quelle sie erzeugt – das passt zu Server-Sent Events und zu weitergeleiteten LLM-Token-Streams, bei denen die Verbindung sekundenlang offen bleibt. Persistente bidirektionale Protokolle wie WebSockets laufen weiterhin über Django Channels statt über reine HTTP-Views, doch beide ruhen auf demselben ASGI-Fundament. Ein Projekt, das Async Views einführt, hat die Infrastrukturkosten für spätere Echtzeitfunktionen damit bereits getragen. ## Die Wahl eines Django-ASGI-Servers 2026 Django liefert in `asgi.py` ein ASGI-Anwendungsobjekt, führt sich aber nicht selbst aus; ein dedizierter ASGI-Server treibt den Event Loop an. Die [ASGI-Spezifikation](https://asgi.readthedocs.io/en/latest/) definiert die Schnittstelle, die jeder dieser Server implementiert – deshalb sind sie auf Protokollebene austauschbar und unterscheiden sich vor allem in Performance und Protokollabdeckung. | Server | Implementiert in | Am besten geeignet für | |--------|----------------|----------| | Uvicorn | Python (uvloop) | Allgemeines ASGI, HTTP/1.1, gängiger Standard | | Daphne | Python | Django Channels, WebSockets, HTTP/2 | | Granian | Rust | Höchster reiner Durchsatz, HTTP/1 und HTTP/2 | | Hypercorn | Python | HTTP/2 und HTTP/3 (QUIC) | Für die meisten Deployments 2026 bleibt [Uvicorn](https://www.uvicorn.org/), betrieben als Gunicorn-Worker-Klasse, die verlässliche Wahl: Gunicorn überwacht den Prozess-Lebenszyklus, startet abgestürzte Worker neu und verarbeitet Signale, während Uvicorn in jedem Worker den Event Loop antreibt. Ein Migrationsdetail bringt Upgrades ins Stolpern: Die Gunicorn-Worker-Klassen sind mit Uvicorn 0.30 aus dem Uvicorn-Core in ein separates `uvicorn-worker`-Paket ausgelagert worden, sodass sich der Import-Pfad geändert hat. ```bash # Zuerst das Worker-Paket installieren: pip install uvicorn-worker gunicorn myproject.asgi:application \ --workers 4 \ --worker-class uvicorn_worker.UvicornWorker \ --bind 0.0.0.0:8000 ``` Teams, die maximalen Durchsatz anstreben, greifen zunehmend zu Granian, einem Rust-basierten Server, der den HTTP-Parsing-Overhead auf Python-Seite eliminiert. Unabhängig von der Wahl ist die Deployment-Geschichte der Grund, warum Async nur dann in Produktion auftaucht, wenn es bewusst konfiguriert wird; das ASGI-spezifische Setup spiegelt die operative Sorgfalt wider, die im Modul zu den [Django-Deployment-Interview-Fragen](/technologies/django/interview-questions/django-deployment) behandelt wird. ## Das Async-ORM und die SynchronousOnlyOperation-Falle Django 4.1 hat asynchrone Query-Methoden über das gesamte ORM hinweg ergänzt: `aget`, `acreate`, `asave`, `adelete`, `acount`, `aexists`, `aaggregate` sowie Iteration mit `async for`. Sie bieten eine async-freundliche Oberfläche, doch ein entscheidender Vorbehalt bleibt bis 2026 bestehen: Die darunterliegende Datenbankschicht ist nicht nativ asynchron. Selbst mit psycopg3 führt Django Abfragen in einem Threadpool aus und stellt sie über async-Wrapper bereit. Das Async-ORM verbessert also die Ergonomie und vermeidet ein Blockieren des Loops, ohne echte durchgängige asynchrone Datenbank-I/O zu liefern. Der häufigste Fehlerfall ist der direkte Aufruf einer synchronen ORM-Methode innerhalb einer Async View. Django erkennt den asynchronen Kontext und verweigert ihn, indem es `SynchronousOnlyOperation` auslöst – um zu verhindern, dass ein blockierender Aufruf den Event Loop für jede andere Anfrage einfriert, die sich denselben Worker teilt. > **SynchronousOnlyOperation ist ein Feature** > > Die Ausnahme ist eine Schutzvorrichtung, kein Bug. Zu `DJANGO_ALLOW_ASYNC_UNSAFE=true` zu greifen, um sie zum Schweigen zu bringen, führt genau das blockierende Verhalten wieder ein, das Async beseitigen sollte. Die korrekte Lösung ist eine Async-ORM-Methode (`aget` statt `get`) oder ein expliziter `sync_to_async`-Wrapper um Code, der kein asynchrones Äquivalent besitzt. Async Views lesen sich sauber, sobald die asynchronen Query-Methoden ihre synchronen Pendants ersetzen. Das folgende Muster zählt Zeilen und streamt die ersten zehn Datensätze, ohne den Event Loop je zu verlassen. ```python # views.py from django.http import JsonResponse from .models import Article async def latest_articles(request): # acount() und async-Iteration sind async-sichere Wrapper um das ORM. count = await Article.objects.acount() titles = [] async for article in Article.objects.order_by("-created_at")[:10]: titles.append(article.title) return JsonResponse({"count": count, "titles": titles}) ``` Für manchen Code gibt es kein asynchrones Gegenstück: ein Drittanbieter-SDK, das nur synchrone Aufrufe anbietet, oder eine dichte Kette von ORM-Traversierungen, deren Umschreibung sich nicht lohnt. Das Umschließen mit `sync_to_async` aus der [asgiref-Bibliothek](https://github.com/django/asgiref) lagert die Arbeit in einen Thread aus und hält den Loop reaktionsfähig. Das Argument `thread_sensitive=True` ist der sichere Standard, weil es jeden umschlossenen Aufruf an einen einzigen gemeinsam genutzten Executor-Thread leitet und so den Zustand von Datenbankverbindung und Transaktion bewahrt, der zerbrechen würde, wenn sich die Aufrufe über beliebige Threads verteilten. ```python # views.py from asgiref.sync import sync_to_async from .services import build_report # eine synchrone Funktion async def report_view(request): # thread_sensitive=True hält umschlossene Aufrufe auf einem gemeinsamen Thread # und bewahrt Verbindungs- und Transaktionszustand über die Grenze hinweg. report = await sync_to_async(build_report, thread_sensitive=True)(request.user.id) return JsonResponse(report) ``` ## Django Async Performance: Wann Nebenläufigkeit gewinnt Django Async Performance ist eine Geschichte über die Überlappung von I/O, nicht über rohe Geschwindigkeit. Der klarste Gewinn ergibt sich, wenn unabhängige Netzwerkaufrufe mit `asyncio.gather` aufgefächert werden: Drei externe Anfragen zu je 200 ms kosten sequenziell rund 600 ms, laufen nebenläufig aber in etwa 200 ms ab, weil sich die Awaits auf demselben Loop überlappen. ```python # views.py import asyncio import httpx from django.http import JsonResponse async def aggregate(request): async with httpx.AsyncClient(timeout=5.0) as client: # Drei unabhängige Aufrufe laufen nebenläufig statt nacheinander. weather, prices, news = await asyncio.gather( client.get("https://api.example.com/weather"), client.get("https://api.example.com/prices"), client.get("https://api.example.com/news"), ) return JsonResponse({ "weather": weather.json(), "prices": prices.json(), "news": news.json(), }) ``` Der umgekehrte Fall ist genauso wichtig. Eine View, die eine einzelne schnelle lokale Abfrage ausführt, gewinnt durch Async nichts und verliert oft, weil nun jede Anfrage das Scheduling des Event Loops plus einen Threadpool-Sprung in den synchronen Datenbanktreiber bezahlt. Async erhebt außerdem an jeder sync/async-Grenze eine subtilere Steuer: Das Mischen synchroner und asynchroner Middleware zwingt Django, bei jedem Übergang zwischen Loop und Thread zu wechseln, und eine Anfrage, die diese Grenze mehrfach pro Antwort überschreitet, sammelt spürbare Latenz an. Einen einheitlich asynchronen oder einheitlich synchronen Middleware-Stack zu halten, beseitigt diese Wechsel. Die Entscheidung reduziert sich auf die Form der Arbeitslast statt auf eine Vorliebe für moderne Syntax. | Arbeitslast | Besserer Standard | |----------|----------------| | Mehrere langsame externe API-Aufrufe pro Anfrage | Async View mit `asyncio.gather` | | Langlebiges Streaming oder Server-Sent Events | Async View mit asynchronem Generator | | Einzelne schnelle Datenbankabfrage, CPU-leicht | Sync View, mehr Gunicorn-Worker | | CPU-gebundenes Rendering oder Berechnung | Sync View, Auslagern an eine Task-Queue | Für wirklich langlaufende Jobs sind Async Views das gänzlich falsche Werkzeug; eine Anfrage offenzuhalten, um minutenlange Arbeit zu verrichten, verschwendet die Verbindung unabhängig vom Nebenläufigkeitsmodell. Diese Arbeit gehört in einen Hintergrund-Worker – ein Tradeoff, der im Leitfaden zu [Celery Async Tasks in Django](/blog/django/django-celery-async-tasks-interview-2026) untersucht wird. Die Einführung sollte auf Messung folgen, nicht auf Intuition. Der ehrliche Weg, Async zu rechtfertigen, besteht darin, den konkreten Endpunkt mit einem Werkzeug wie Locust oder k6 unter realistischer Nebenläufigkeit zu lasttesten und eine synchrone Version auf N Workern gegen eine asynchrone Version auf derselben Hardware zu vergleichen. Endpunkte, die von einem einzelnen externen Aufruf mit hoher Latenz dominiert werden, zeigen einen weiten Abstand zugunsten von Async; Endpunkte, die von schnellen Abfragen dominiert werden, zeigen Async häufig leicht im Rückstand, sobald der Threadpool-Sprung mitgerechnet wird. Die Anfrage zuerst zu profilen offenbart zudem, ob der Flaschenhals überhaupt I/O ist, denn Async bringt nichts für eine View, die wegen nicht indizierter Abfragen langsam ist – ein Problem, das die Anleitung zur [Optimierung von Django-ORM-Abfragen](/blog/django/django-orm-optimizing-queries) behandelt. ## Django Async Interview-Fragen für 2026 Ein Django-Async-Interview prüft, ob ein Kandidat das Modell versteht oder lediglich die Schlüsselwörter wiedererkennt. Die folgenden Fragen spiegeln wider, was Senior-Interviews 2026 tatsächlich abfragen – jeweils gepaart mit der Antwort, die ein erfahrener Entwickler gibt. **Was ändert sich, wenn eine Async View unter WSGI statt unter ASGI läuft?** Unter WSGI umschließt Django die Coroutine mit `async_to_sync` und führt sie vollständig auf dem Anfrage-Thread aus, sodass sie sich wie eine langsamere synchrone View ohne jeden Nebenläufigkeitsvorteil verhält. Erst ein ASGI-Server mit laufendem Event Loop lässt den Worker während eines `await` andere Anfragen bedienen. **Warum löst `Article.objects.get(pk=1)` innerhalb einer Async View `SynchronousOnlyOperation` aus?** Der synchrone ORM-Aufruf würde den Event Loop blockieren und jede andere Anfrage auf diesem Worker anhalten. Django erkennt den asynchronen Kontext und verweigert ihn. Die Lösung ist die Async-Methode `await Article.objects.aget(pk=1)` oder `sync_to_async` für Code ohne asynchrones Äquivalent. **Ist das Async-ORM von Django wirklich nicht-blockierend?** Nein. Die Async-Methoden sind ergonomische Wrapper; die zugrunde liegenden Abfragen laufen weiterhin in einem Threadpool, weil die Datenbanktreiber nicht durchgängig für native asynchrone Ausführung integriert sind. Der Vorteil liegt darin, den Loop frei zu halten, nicht in paralleler Datenbank-I/O auf Treiberebene. **Wann sollten Async Views einer Task-Queue wie Celery vorgezogen werden?** Async Views eignen sich für anfragebezogene I/O-Nebenläufigkeit, die vor der Antwort abgeschlossen sein muss, etwa das Aggregieren mehrerer APIs. Arbeit, die die Anfrage überdauert, Retries benötigt oder minutenlang läuft, gehört in Celery oder in Djangos Background Tasks, da das Offenhalten einer HTTP-Verbindung dafür Serverressourcen verschwendet. **Was kostet das Mischen von synchroner und asynchroner Middleware?** Jeder Übergang zwischen einer synchronen und einer asynchronen Komponente zwingt Django, über `sync_to_async` oder `async_to_sync` zwischen Event Loop und Thread zu springen. Eine Anfrage, die diese Grenze wiederholt überschreitet, zahlt kumulativen Overhead, sodass ein einheitlicher Middleware-Stack besser abschneidet als ein verschachtelter. ## Fazit - Async Views liefern Nebenläufigkeit nur auf einem ASGI-Server; dieselbe View läuft unter WSGI synchron über `async_to_sync`. - Uvicorn über das `uvicorn-worker`-Paket unter Gunicorn deployen, oder Granian für maximalen Durchsatz, und das ASGI-Setup als expliziten Deployment-Schritt behandeln. - Zu Async Views greifen, wenn eine Anfrage auf mehrere langsame externe I/O-Aufrufe wartet; Endpunkte mit schnellen Abfragen und CPU-gebundene Endpunkte synchron mit mehr Workern halten. - `aget`, `acreate` und `async for` innerhalb von Async Views verwenden und daran denken, dass das ORM Abfragen weiterhin in einem Threadpool ausführt statt nativ asynchron. - `SynchronousOnlyOperation` als Schutzvorrichtung behandeln: mit Async-Methoden oder `sync_to_async(thread_sensitive=True)` beheben, niemals durch Deaktivieren der Prüfung. - Den Middleware-Stack einheitlich synchron oder asynchron halten, um an jeder Grenzüberschreitung eine Thread-Wechsel-Strafe zu vermeiden. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/de/blog/django/django-async-views-asgi-2026