Eröffnungsgedanken
Wie sind Sie zu dem Schluss gekommen, dass einige Teile des Systems in einer anderen Sprache besser abschneiden würden? Leiden Sie unter Leistungsproblemen? Wie gravierend sind diese Probleme? Wenn es schneller sein kann, ist es wichtig, dass es schneller ist?
Single-Thread-Asynchronität
Es gibt verschiedene Fragen und andere Webressourcen, die sich bereits mit den Unterschieden, Vor- und Nachteilen von Single-Thread-Asynchronität und Multi-Thread-Parallelität befassen. Es ist interessant zu lesen, wie sich das asynchrone Single-Thread-Modell von Node.js verhält, wenn E / A der größte Engpass ist und viele Anfragen gleichzeitig bearbeitet werden.
Twisted-, Tornado- und andere asynchrone Modelle nutzen einen Single-Thread hervorragend. Da in vielen Webprogrammen viele E / A-Vorgänge (Netzwerk, Datenbank usw.) ausgeführt werden, summiert sich die Wartezeit für Remoteanrufe erheblich. In dieser Zeit könnten Sie andere Dinge erledigen - z. B. andere Datenbankaufrufe starten, Seiten rendern und Daten generieren. Die Auslastung dieses Single-Threads ist extrem hoch.
Einer der größten Vorteile der Singlethread-Asynchronität besteht darin, dass viel weniger Arbeitsspeicher benötigt wird. Bei der Ausführung mit mehreren Threads benötigt jeder Thread eine bestimmte Menge an reserviertem Speicher. Wenn die Anzahl der Threads zunimmt, nimmt auch die Speichermenge zu, die nur für das Vorhandensein der Threads erforderlich ist. Da der Speicher endlich ist, gibt es Grenzen für die Anzahl der Threads, die gleichzeitig erstellt werden können.
Beispiel
Stellen Sie sich im Fall eines Webservers vor, dass jede Anforderung einen eigenen Thread erhält. Angenommen, für jeden Thread ist 1 MB Arbeitsspeicher erforderlich, und der Webserver verfügt über 2 GB RAM. Dieser Webserver kann zu jedem Zeitpunkt (ungefähr) 2000 Anforderungen verarbeiten, bevor nicht mehr genügend Arbeitsspeicher für die Verarbeitung vorhanden ist.
Wenn Ihre Auslastung wesentlich höher ist, wird es sehr lange dauern, bis die Anforderungen abgeschlossen sind (wenn Sie darauf warten, dass ältere Anforderungen ausgeführt werden), oder Sie müssen mehr Server in den Cluster werfen, um die Anzahl der gleichzeitig möglichen Anforderungen zu erhöhen .
Multi-Thread-Parallelität
Die gleichzeitige Ausführung mehrerer Threads erfordert stattdessen die gleichzeitige Ausführung mehrerer Aufgaben. Das heißt, wenn ein Thread blockiert ist und auf die Rückgabe eines Datenbankaufrufs wartet, können gleichzeitig andere Anforderungen verarbeitet werden. Die Thread-Auslastung ist geringer, aber die Anzahl der ausgeführten Threads ist viel größer.
Multi-Thread-Code ist auch viel schwieriger zu überlegen. Es gibt Probleme mit dem Sperren, der Synchronisierung und anderen unterhaltsamen Problemen bei der gemeinsamen Nutzung. Single-Thread-Asynchronität leidet nicht unter denselben Problemen.
Multi-Thread-Code ist jedoch für CPU-intensive Aufgaben viel leistungsfähiger . Wenn es für einen Thread keine Möglichkeit gibt, "nachzugeben" - wie bei einem Netzwerkaufruf, der normalerweise blockiert würde -, hat ein Single-Thread-Modell keinerlei Parallelität.
Beide können koexistieren
Es gibt natürlich eine Überlappung zwischen den beiden; sie schließen sich nicht aus. Beispielsweise kann Multithread-Code nicht blockierend geschrieben werden, um jeden Thread besser zu nutzen.
Die Quintessenz
Es gibt noch viele andere Punkte zu beachten, aber ich denke gerne über diese beiden Punkte nach:
- Wenn Ihr Programm E / A-gebunden ist , wird die Single-Thread-Asynchronität wahrscheinlich recht gut funktionieren.
- Wenn Ihr Programm CPU-gebunden ist , ist ein Multithread-System wahrscheinlich das Beste.
In Ihrem speziellen Fall müssen Sie bestimmen, welche Art von asynchroner Arbeit ausgeführt wird und wie oft diese Aufgaben auftreten.
- Treten sie bei jeder Anfrage auf? In diesem Fall wird der Speicher wahrscheinlich zu einem Problem, wenn die Anzahl der Anforderungen steigt.
- Sind diese Aufgaben bestellt? In diesem Fall müssen Sie die Synchronisierung in Betracht ziehen, wenn Sie mehrere Threads verwenden.
- Sind diese Aufgaben CPU-intensiv? Wenn ja, kann ein einzelner Thread mit der Last mithalten?
Es gibt keine einfache Antwort. Sie müssen Ihre Anwendungsfälle berücksichtigen und entsprechend gestalten. Manchmal ist ein asynchrones Single-Thread-Modell besser. In anderen Fällen ist die Verwendung einer Reihe von Threads erforderlich, um eine massive Parallelverarbeitung zu erreichen.
Andere Überlegungen
Es gibt noch andere Aspekte, die Sie berücksichtigen müssen, und nicht nur das von Ihnen gewählte Parallelitätsmodell. Kennen Sie Erlang oder Clojure? Glauben Sie, dass Sie in der Lage sind, sicheren Multithread-Code in einer dieser Sprachen zu schreiben, um die Leistung Ihrer Anwendung zu verbessern? Wird es lange dauern, bis Sie mit einer dieser Sprachen vertraut sind, und wird die Sprache, die Sie lernen, Ihnen in Zukunft zugute kommen?
Wie steht es mit den Kommunikationsschwierigkeiten zwischen diesen beiden Systemen? Wird es zu komplex sein, zwei separate Systeme parallel zu warten? Wie erhält das Erlang-System Aufgaben von Django? Wie wird Erlang diese Ergebnisse an Django zurückmelden? Ist die Leistung so bedeutend, dass sich die zusätzliche Komplexität lohnt?
Abschließende Gedanken
Ich habe immer festgestellt, dass Django schnell genug ist und von einigen sehr stark frequentierten Websites verwendet wird. Sie können verschiedene Leistungsoptimierungen vornehmen, um die Anzahl der gleichzeitigen Anforderungen und die Antwortzeit zu erhöhen. Zugegeben, ich habe bisher noch nichts mit Celery gemacht, sodass die üblichen Leistungsoptimierungen wahrscheinlich keine Probleme lösen werden, die bei diesen asynchronen Aufgaben auftreten können.
Natürlich gibt es immer den Vorschlag, das Problem mit mehr Hardware zu lösen. Sind die Kosten für die Bereitstellung eines neuen Servers günstiger als die Entwicklungs- und Wartungskosten eines völlig neuen Subsystems?
Ich habe zu diesem Zeitpunkt viel zu viele Fragen gestellt, aber das war meine Absicht. Die Antwort wird ohne Analyse und weitere Details nicht einfach sein. In der Lage zu sein, die Probleme zu analysieren, bedeutet jedoch, die zu stellenden Fragen zu kennen. Hoffentlich habe ich dabei geholfen.
Mein Bauchgefühl sagt, dass ein Umschreiben in einer anderen Sprache nicht notwendig ist. Die Komplexität und die Kosten werden wahrscheinlich zu groß sein.
Bearbeiten
Reaktion auf das Follow-up
Ihr Follow-up präsentiert einige sehr interessante Anwendungsfälle.
1. Django arbeitet außerhalb von HTTP-Anfragen
In Ihrem ersten Beispiel haben Sie NFC-Tags gelesen und anschließend die Datenbank abgefragt. Ich denke nicht, dass das Schreiben dieses Teils in einer anderen Sprache für Sie so nützlich sein wird, da das Abfragen der Datenbank oder eines LDAP-Servers an die Netzwerk-E / A (und möglicherweise die Datenbankleistung) gebunden ist. Andererseits wird die Anzahl der gleichzeitigen Anforderungen vom Server selbst festgelegt, da jeder Verwaltungsbefehl als eigener Prozess ausgeführt wird. Es wird Setup- und Teardown-Zeiten geben, die sich auf die Leistung auswirken, da Sie keine Nachrichten an einen bereits laufenden Prozess senden. Sie können jedoch mehrere Anforderungen gleichzeitig senden, da es sich jeweils um einen isolierten Prozess handelt.
Für diesen Fall sehe ich zwei Möglichkeiten, die Sie untersuchen können:
- Stellen Sie sicher, dass Ihre Datenbank mit dem Verbindungspooling mehrere Abfragen gleichzeitig verarbeiten kann. (Oracle erfordert beispielsweise, dass Sie Django entsprechend konfigurieren
'OPTIONS': {'threaded':True}
.) Auf Datenbank- oder Django-Ebene gibt es möglicherweise ähnliche Konfigurationsoptionen, die Sie für Ihre eigene Datenbank anpassen können. Unabhängig davon, in welcher Sprache Sie Ihre Datenbankabfragen schreiben, müssen Sie auf die Rückgabe dieser Daten warten, bevor Sie die LEDs aufleuchten lassen können. Die Leistung des Abfragecodes kann jedoch einen Unterschied machen, und der Django ORM ist nicht blitzschnell ( aber normalerweise schnell genug).
- Rüst- / Abbauzeit minimieren. Haben Sie einen ständig laufenden Prozess und senden Sie Nachrichten an ihn. (Korrigieren Sie mich, wenn ich falsch liege, aber genau darauf konzentriert sich Ihre ursprüngliche Frage.) Ob dieser Prozess in Python / Django oder in einer anderen Sprache / einem anderen Framework geschrieben ist, wird oben behandelt. Mir gefällt die Idee nicht, Verwaltungsbefehle so häufig zu verwenden. Ist es möglich, dass ständig ein kleines Stück Code läuft, das Nachrichten von den NFC-Lesern in die Nachrichtenwarteschlange schiebt, die Sellerie dann liest und an Django weiterleitet? Das Einrichten und Herunterfahren eines kleinen Programms, auch wenn es in Python geschrieben ist (aber nicht in Django!), Sollte besser sein, als ein Django-Programm (mit all seinen Subsystemen) zu starten und zu stoppen.
Ich bin mir nicht sicher, welchen Webserver Sie für Django verwenden. mod_wsgi
Mit for Apache können Sie die Anzahl der Prozesse und Threads in den Prozessen konfigurieren, für die Serviceanforderungen gestellt werden. Stellen Sie sicher, dass Sie die entsprechende Konfiguration Ihres Webservers anpassen, um die Anzahl der wartbaren Anforderungen zu optimieren.
2. "Message-Passing" mit Django-Signalen
Ihr zweiter Anwendungsfall ist ebenfalls ziemlich interessant. Ich bin mir nicht sicher, ob ich die Antworten dafür habe. Wenn Sie Modellinstanzen löschen und sie später bearbeiten möchten, können Sie sie möglicherweise serialisieren JSON.dumps
und anschließend deserialisieren JSON.loads
. Es ist später unmöglich, das Objektdiagramm vollständig neu zu erstellen (Abfragen verwandter Modelle), da verwandte Felder nur schleppend aus der Datenbank geladen werden und diese Verknüpfung nicht mehr besteht.
Die andere Möglichkeit wäre, ein Objekt zum Löschen zu markieren und erst am Ende des Anforderungs- / Antwortzyklus zu löschen (nachdem alle Signale bearbeitet wurden). Möglicherweise ist ein benutzerdefiniertes Signal erforderlich, um dies zu implementieren, anstatt sich darauf zu verlassen post_delete
.