/ / Wie wird ReactiveMongo implementiert, damit es als nicht blockierend gilt? - scala, playframework, reaktives programmieren, reaktivieren, iterieren

Wie wird ReactiveMongo implementiert, so dass es als nicht blockierend gilt? - scala, playframework, reaktive Programmierung, reactivemongo, iterate

Das Lesen der Dokumentation über das Play Framework und ReactiveMongo lässt mich glauben, dass ReactiveMongo so arbeitet, dass es wenige Threads verwendet und niemals blockiert.

Es scheint jedoch, dass die Kommunikation von der Play-Anwendung zum Mongo-Server weitergeleitet werden müsste irgendwo ein Thread. Wie wird das umgesetzt? Links zum Quellcode für Play, ReactiveMongo, Akka usw. sind ebenfalls sehr willkommen.

Das Play Framework enthält auf dieser Seite einige Dokumentationen über Thread-Pools. Es geht los:

Das Play Framework ist von Grund auf ein asynchrones Web-Framework. Streams werden asynchron mit Iteraten verarbeitet. Thread-Pools in Play sind darauf abgestimmt, verwendet zu werden weniger Threads als in herkömmlichen Web-Frameworks, da IO im Play-Core niemals blockiert.

Es spricht dann ein wenig über ReactiveMongo:

Der häufigste Ort, der ein typisches Spiel darstelltAnwendung blockiert ist, wenn es mit einer Datenbank spricht. Leider stellt keine der Hauptdatenbanken asynchrone Datenbanktreiber für die JVM zur Verfügung. Für die meisten Datenbanken besteht die einzige Möglichkeit darin, blockierende E / A zu verwenden. EIN Eine bemerkenswerte Ausnahme ist ReactiveMongoein Treiber für MongoDB, der die Iteratee-Bibliothek von Play für die Kommunikation mit MongoDB verwendet

Nachfolgend ein Hinweis zur Verwendung von Futures:

Beachten Sie, dass Sie möglicherweise versucht sind, Ihren Sperrcode in Futures einzugeben. Dies macht es nicht blockierend, es bedeutet nur das Die Blockierung erfolgt in einem anderen Thread. Sie müssen weiterhin sicherstellen, dass der Thread-Pool, den Sie dort verwenden, über genügend Threads verfügt, um die Blockierung zu handhaben.

Ein ähnlicher Hinweis befindet sich in der Play-Dokumentation auf der Seite Umgang mit asynchronen Ergebnissen:

Sie können ein synchrones IO nicht magisch in asynchrones verwandeln, indem Sie es in eine Zukunft packen. Wenn Sie die Architektur der Anwendung nicht ändern können, um das Blockieren von Vorgängen zu vermeiden, irgendwann muss diese Operation ausgeführt werden und der Thread wird blockieren. Also neben der Operation in ein einschließenZukünftig ist es erforderlich, es für die Ausführung in einem separaten Ausführungskontext zu konfigurieren, der mit genügend Threads für die erwartete Parallelität konfiguriert wurde.

Die Dokumentation scheint das zu sagenReactiveMongo ist nicht blockierend, sodass Sie sich keine Sorgen darüber machen müssen, dass es viele Threads in Ihrem Thread-Pool verbraucht. ReactiveMongo muss jedoch mit dem Mongo-Server kommunizieren irgendwo.

Wie wird diese Kommunikation implementiert, damit Mongo keine Threads aus dem Standard-Thread-Pool von Play verwendet?

Wieder einmal Links zu den spezifischen Dateien in abspielen, ReactiveMongo, Akkausw. wäre sehr dankbar.

Antworten:

11 für die Antwort № 1

Ja, in der Tat müssen Sie immer noch Threads verwenden, um jegliche Art von Arbeit auszuführen, einschließlich der Kommunikation mit der Datenbank. Was ist wichtig ist wie genau diese Kommunikation geschieht.

ReactiveMongo "verwendet keine Threads" in einem Sinn, den es nicht verwendet Blockieren der E / A. Übliche Java-E / A-Funktionen wie java.io.InputStream blockieren; Dies bedeutet, dass das Lesen von einem solchen InputStream oder schreiben an OutputStream blockiert den Thread, bis die "andere Seite" die erforderlichen Daten bereitstellt oder bereit ist, sie anzunehmen Für die Netzwerkkommunikation bedeutet dies, dass Threads werden blockiert werden.

Java bietet jedoch NIO-API die unterstützt nicht blockierend und asynchron I / O. Ich möchte jetzt nicht auf Details eingehen, aber die grundlegende Idee ist natürlich, dass nicht blockierende E / A-Threads es nicht zulassen, Threads, die einige Daten mit der Außenwelt austauschen müssen, zu blockieren Rufen Sie die Datenquelle ab, um zu prüfen, ob Daten verfügbar sind, und wenn keine Daten vorhanden sind, kehren sie zum Thread-Pool zurück und können für andere Aufgaben verwendet werden. Diese Funktionen werden natürlich vom zugrunde liegenden Betriebssystem bereitgestellt.

Genaue Implementierungsdetails für nicht blockierende E / A sind normalerweise in Bibliotheken höherer Ebene versteckt, wie z Netty denn es ist überhaupt nicht schön zu bedienen. Netty (genau die Bibliothek, die von ReactiveMongo verwendet wird) bietet beispielsweise eine asynchrone, callback-artige API, die einfach zu verwenden ist, aber auch so leistungsfähig und ausdrucksstark ist, dass komplexe E / A-Anwendungen mit hohem Durchsatz erstellt werden können.

ReactiveMongo verwendet Netty, um mit Mongo zu sprechenDatenbankserver und da Netty eine Implementierung asynchroner Netzwerk-E / A ist, muss ReactiveMongo Threads wirklich nicht lange Zeit blockieren.