Asynchrone Views und WebSocket-Integration in Flask 2.x
Olivia Novak
Dev Intern · Leapcell

Einführung
In der sich ständig weiterentwickelnden Landschaft der Backend-Entwicklung sind Reaktionsfähigkeit und Echtzeitfähigkeiten von wünschenswerten Features zu wesentlichen Anforderungen geworden. Traditionelle synchrone Python-Frameworks sind zwar robust, stoßen aber oft an ihre Grenzen, wenn es um E/A-gebundene Operationen wie Datenbankabfragen, externe API-Aufrufe oder Long-Polling-Anfragen geht. Dies kann zu erhöhter Latenz und reduziertem Durchsatz führen, insbesondere unter hoher Last. Das Aufkommen von async/await
in Python, gepaart mit seiner nahtlosen Integration in Flask 2.x, bietet eine leistungsstarke Lösung für diese Herausforderungen und ermöglicht es Entwicklern, hochgradig nebenläufige und skalierbare Webanwendungen zu erstellen. Darüber hinaus hat die steigende Nachfrage nach sofortiger, bidirektionaler Kommunikation zwischen Clients und Servern WebSockets in den Vordergrund gerückt und die Art und Weise, wie wir interaktive Funktionen entwickeln, verändert. Dieser Artikel untersucht, wie Flask 2.x Entwickler in die Lage versetzt, asynchrone Ansichten für verbesserte Leistung zu nutzen und WebSockets für reichhaltige Echtzeit-Benutzererlebnisse zu integrieren, und legt damit den Grundstein für die Entwicklung moderner, reaktionsfähiger Webdienste.
Kernkonzepte und Mechanismen
Bevor wir uns mit den Implementierungsdetails befassen, wollen wir einige grundlegende Konzepte klären, die für das Verständnis asynchroner Programmierung und WebSocket-Kommunikation in Flask entscheidend sind.
Asynchrone Programmierung (async/await): Dieses Paradigma ermöglicht es einem Programm, eine E/A-Operation (z. B. das Lesen aus einer Datenbank) zu starten und, anstatt auf deren Abschluss zu warten, zu anderen Aufgaben zu wechseln. Sobald die E/A-Operation abgeschlossen ist, kann das Programm die ursprüngliche Aufgabe wieder aufnehmen. In Python definiert async
eine "Koroutine" (eine asynchrone Funktion), und await
pausiert die Ausführung einer Koroutine, bis ein awaitable (wie eine andere Koroutine oder eine E/A-Operation) abgeschlossen ist. Diese nicht-blockierende Natur verbessert die Nebenläufigkeit erheblich, ohne sich auf traditionelles Multithreading zu verlassen, das oft mit Overhead durch Kontextwechsel und Ressourcenkonflikte verbunden ist.
ASGI (Asynchronous Server Gateway Interface): So wie WSGI (Web Server Gateway Interface) die Schnittstelle zwischen Python-Webservern und synchronen Webanwendungen standardisierte, tut dies ASGI für asynchrone Anwendungen. Die Unterstützung von Flask 2.x für ASGI ermöglicht es ihm, auf asynchronen Servern wie Uvicorn oder Hypercorn ausgeführt zu werden, die für die effiziente Handhabung nebenläufiger asynchroner Anfragen entwickelt wurden.
WebSockets: Im Gegensatz zum Request-Response-Modell von HTTP bieten WebSockets einen Full-Duplex-Kommunikationskanal über eine einzige, langlebige TCP-Verbindung. Das bedeutet, dass sowohl der Client als auch der Server jederzeit Nachrichten austauschen können, was Echtzeitinteraktionen wie Chat-Anwendungen, Live-Dashboards oder kollaborative Tools ermöglicht. Nach einem anfänglichen HTTP-Handshake wird die Verbindung zu einem WebSocket "upgegraded", was einen persistenten Datenaustausch mit geringer Latenz ermöglicht.
Asynchrone Ansichten in Flask 2.x
Flask 2.x unterstützt async/await
, indem es die Definition asynchroner Ansichtsfunktionen ermöglicht. Dies ist besonders vorteilhaft für E/A-gebundene Operationen, die andernfalls den gesamten Serverprozess blockieren würden.
Betrachten Sie eine synchrone Flask-Ansicht:
from flask import Flask, jsonify import time app = Flask(__name__) @app.route("/sync-data") def get_sync_data(): time.sleep(2) # Simulieren einer blockierenden E/A-Operation return jsonify({"message": "Data fetched synchronously"}) if __name__ == "__main__": app.run(debug=True)
In diesem Beispiel, wenn mehrere Clients gleichzeitig /sync-data
aufrufen, muss jede Anfrage nacheinander auf den Abschluss des 2-Sekunden-time.sleep()
warten, was zu schlechter Leistung führt.
Schreiben wir es nun mit einer asynchronen Ansicht neu:
from flask import Flask, jsonify import asyncio app = Flask(__name__) @app.route("/async-data") async def get_async_data(): await asyncio.sleep(2) # Simulieren einer nicht-blockierenden E/A-Operation return jsonify({"message": "Data fetched asynchronously"}) if __name__ == "__main__": # Um async-Ansichten auszuführen, benötigen Sie einen ASGI-Server wie Uvicorn # Sie würden dies typischerweise mit `uvicorn your_app_file:app --reload` ausführen pass
Um dies wirklich asynchron auszuführen, benötigen Sie einen ASGI-Server. Wenn Ihre Datei beispielsweise app.py
heißt, würden Sie sie mit uvicorn app:app --reload
ausführen. Wenn mehrere asynchrone Anfragen /async-data
erreichen, blockiert asyncio.sleep(2)
nicht den Server-Thread; stattdessen kann der Server zu anderen Anfragen oder Aufgaben wechseln, während er auf den Abschluss des Sleeps wartet. Dies verbessert die Fähigkeit der Anwendung, nebenläufige Verbindungen zu verarbeiten, erheblich. Sie können aiohttp
für externe API-Aufrufe, asyncpg
für PostgreSQL oder aiomysql
für MySQL auf ähnliche nicht-blockierende Weise integrieren.
WebSocket-Unterstützung
Flask selbst hat keine native, integrierte WebSocket-Unterstützung. Es kann jedoch nahtlos mit einer Flask-Erweiterung wie Flask-SocketIO
integriert oder direkt ein ASGI-Toolkit verwendet werden, das WebSockets neben Flask unterstützt. Der Einfachheit und weiten Verbreitung halber konzentrieren wir uns auf Flask-SocketIO
, da es eine Abstraktion auf höherer Ebene bietet.
Installieren Sie zunächst die notwendigen Bibliotheken:
pip install Flask Flask-SocketIO eventlet
eventlet
(oder gevent
) wird von Flask-SocketIO
benötigt, um die Standardbibliothek von Python als nicht-blockierend zu patchen. Für echte async/await
-WebSockets mit ASGI können Sie python-socketio
direkt mit einem ASGI-Server verwenden.
Hier ist ein Beispiel für eine einfache Chat-Anwendung mit Flask-SocketIO:
from flask import Flask, render_template from flask_socketio import SocketIO, emit app = Flask(__name__) app.config['SECRET_KEY'] = 'your_secret_key' # Ersetzen Sie dies durch einen starken geheimen Schlüssel socketio = SocketIO(app, async_mode='eventlet') # 'async_mode' kann 'gevent', 'threading' oder 'asyncio' mit uvicorn sein @app.route('/') def index(): return render_template('index.html') @socketio.on('message') def handle_message(data): print(f"Received message: {data['data']}") emit('my response', {'data': data['data']}, broadcast=True) @socketio.on('connect') def test_connect(): print("Client connected") emit('my response', {'data': 'Connected!'}) @socketio.on('disconnect') def test_disconnect(): print("Client disconnected") if __name__ == '__main__': # Für Eventlet mit `socketio.run()` ausführen socketio.run(app, debug=True)
Und die entsprechende templates/index.html
-Datei:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Flask WebSocket Chat</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.0/socket.io.js"></script> <script type="text/javascript" charset="utf-8"> var socket = io(); socket.on('connect', function() { socket.emit('message', {data: 'I\'m connected!'}); }); socket.on('my response', function(msg) { document.getElementById('messages').innerHTML += '<p>' + msg.data + '</p>'; }); function sendMessage() { var input = document.getElementById('chatInput'); socket.emit('message', {data: input.value}); input.value = ''; } </script> </head> <body> <h1>Flask WebSocket Chat</h1> <input type="text" id="chatInput" onkeydown="if (event.keyCode == 13) sendMessage()"> <button onclick="sendMessage()">Send</button> <div id="messages"></div> </body> </html>
In diesem Beispiel dekoriert @socketio.on('message')
eine Funktion, die ausgeführt wird, wenn der Client ein message
-Ereignis sendet. Die Zeile emit('my response', ..., broadcast=True)
sendet die empfangene Nachricht zurück an alle verbundenen Clients und erstellt so effektiv einen einfachen Chatroom.
Kombination von Async Views mit WebSockets (ASGI-gesteuert)
Während Flask-SocketIO
mit eventlet
WebSocket-Funktionen bereitstellt, kann für eine wirklich native async/await
-Erfahrung mit Flask 2.x unter Verwendung eines ASGI-Servers python-socketio
direkt integriert werden. Dieser Ansatz passt besser zum async/await
-Paradigma des Flask 2.x-Kerns.
Installieren Sie zunächst speziell python-socketio
für ASGI:
pip install Flask python-socketio aiohttp uvicorn
Hier ist ein Beispiel:
from flask import Flask, render_template_string import socketio import asyncio # Erstellen Sie einen Socket.IO-Server sio = socketio.AsyncServer(async_mode='asgi', cors_allowed_origins='*') # Erstellen Sie eine Flask-App flask_app = Flask(__name__) # Wickeln Sie die Flask-App mit der Socket.IO ASGI-App ein app = socketio.ASGIApp(sio, flask_app) @flask_app.route('/') async def index(): return render_template_string("" <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Flask Async WebSocket Chat</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.0/socket.io.js"></script> <script type="text/javascript" charset="utf-8"> var socket = io(); socket.on('connect', function() { console.log('Connected!'); socket.emit('message', {data: 'I\'m connected async!'}); }); socket.on('my response', function(msg) { document.getElementById('messages').innerHTML += '<p>' + msg.data + '</p>'; }); function sendMessage() { var input = document.getElementById('chatInput'); socket.emit('message', {data: input.value}); input.value = ''; } </script> </head> <body> <h1>Flask Async WebSocket Chat</h1> <input type="text" id="chatInput" onkeydown="if (event.keyCode == 13) sendMessage()"> <button onclick="sendMessage()">Send</button> <div id="messages"></div> </body> </html> ") @sio.on('connect') async def connect(sid, environ): print(f"Client connected: {sid}") await sio.emit('my response', {'data': 'Connected to async server!'}, room=sid) @sio.on('message') async def message(sid, data): print(f"Received message from {sid}: {data['data']}") await sio.emit('my response', data, broadcast=True, skip_sid=sid) # Echo to all but sender await sio.emit('my response', {'data': f"You said: {data['data']}"}, room=sid) # Confirm to sender @sio.on('disconnect') async def disconnect(sid): print(f"Client disconnected: {sid}") if __name__ == '__main__': # Um dies auszuführen, verwenden Sie Uvicorn: `uvicorn your_app_file:app --reload --port 5000` pass
In dieser Konfiguration erstellt sio = socketio.AsyncServer(async_mode='asgi', ...)
einen asynchronen Socket.IO-Server, der mit ASGI kompatibel ist. app = socketio.ASGIApp(sio, flask_app)
umschließt unsere Flask-Anwendung mit der Socket.IO ASGI-Anwendung und ermöglicht es, dass sowohl HTTP-Routen als auch WebSocket-Verbindungen von einem einzigen ASGI-Server wie Uvicorn bedient werden. Die Socket.IO-Ereignisbehandler sind jetzt async
-Funktionen, die perfekt zum async/await
-Paradigma in Flask 2.x passen. Diese leistungsstarke Kombination ermöglicht sowohl hochgradig nebenläufige Webanfragen als auch bidirektionale Echtzeitkommunikation innerhalb eines einheitlichen, asynchronen Frameworks.
Schlussfolgerung
Flask 2.x's Übernahme von async/await
revolutioniert die Art und Weise, wie Entwickler leistungskritische und E/A-gebundene Aufgaben angehen können, und bietet eine robuste Grundlage für die Erstellung skalierbarer Webanwendungen. Gekoppelt mit WebSocket-Unterstützung, sei es über Erweiterungen wie Flask-SocketIO
oder direkte ASGI-Integration, ermöglicht Flask die Erstellung hochgradig interaktiver Echtzeit-Benutzererlebnisse. Durch die Nutzung asynchroner Ansichten und WebSockets können Entwickler moderne, reaktionsfähige Anwendungen erstellen, die Nebenläufigkeit und persistente Kommunikation effizient handhaben, was zu überlegener Benutzerbindung und betrieblicher Effizienz führt. Die Zukunft von Flask ist zweifellos asynchron und in Echtzeit.