Ich bin ein normaler C # -Entwickler, entwickle aber gelegentlich Anwendungen in Java. Ich frage mich, ob es ein Java-Äquivalent von C # async / await gibt. In einfachen Worten, was ist das Java-Äquivalent von:
async Task<int> AccessTheWebAsync()
{
HttpClient client = new HttpClient();
var urlContents = await client.GetStringAsync("http://msdn.microsoft.com");
return urlContents.Length;
}
async
, sondern stattdessenFuture
oderObservable
Werte zu verwenden.Antworten:
Nein, in Java gibt es kein Äquivalent zu async / await - oder sogar in C # vor v5.
Es ist eine ziemlich komplexe Sprachfunktion, eine Zustandsmaschine hinter den Kulissen zu erstellen.
Es gibt relativ wenig Sprachunterstützung für Asynchronität / Parallelität in Java, aber das
java.util.concurrent
Paket enthält viele nützliche Klassen . (Nicht ganz gleichwertig mit der Task Parallel Library, aber der nächsten Annäherung.)quelle
Der
await
verwendet eine Fortsetzung, um zusätzlichen Code auszuführen, wenn die asynchrone Operation abgeschlossen ist (client.GetStringAsync(...)
).Als engste Annäherung würde ich eine
CompletableFuture<T>
(Java 8-Äquivalent zu .netTask<TResult>
) -basierte Lösung verwenden, um die HTTP-Anforderung asynchron zu verarbeiten.AKTUALISIERT am 25-05-2016 auf AsyncHttpClient v.2, veröffentlicht am 13. April 2016:
Das Java 8-Äquivalent zum OP-Beispiel
AccessTheWebAsync()
lautet also wie folgt:Diese Verwendung wurde aus der Antwort auf Wie erhalte ich eine CompletableFuture von einer Async Http Client-Anfrage? und das entspricht der neuen API in Version 2 von AsyncHttpClient bereitgestellt wird und am 13. April 2016 veröffentlicht wurde und die bereits intrinsische Unterstützung für hat
CompletableFuture<T>
.Ursprüngliche Antwort mit Version 1 von AsyncHttpClient:
Zu diesem Zweck haben wir zwei mögliche Ansätze:
Der erste verwendet nicht blockierende E / A und ich nenne es
AccessTheWebAsyncNio
. DaAsyncCompletionHandler
es sich jedoch um eine abstrakte Klasse handelt (anstelle einer funktionalen Schnittstelle), können wir kein Lambda als Argument übergeben. Aufgrund der Syntax anonymer Klassen kommt es daher zu unvermeidlicher Ausführlichkeit. Diese Lösung kommt jedoch dem Ausführungsfluss des angegebenen C # -Beispiels am nächsten .Die zweite ist etwas weniger ausführlich, sendet jedoch eine neue Aufgabe , die letztendlich einen Thread blockiert,
f.get()
bis die Antwort abgeschlossen ist.Erster Ansatz , ausführlicher, aber nicht blockierend:
Zweiter Ansatz weniger ausführlich, aber Blockieren eines Threads:
quelle
Schauen Sie sich ea-async an, bei dem Java-Bytecode neu geschrieben wird, um async / wait ziemlich gut zu simulieren. In ihrer Readme-Datei heißt es: "Es ist stark von Async-Await in der .NET CLR inspiriert."
quelle
asynchron und warten sind syntaktische Zucker. Die Essenz von Async und Warten ist die Zustandsmaschine. Der Compiler wandelt Ihren asynchronen / erwarteten Code in eine Zustandsmaschine um.
Gleichzeitig müssen viele Funktionen der Async-E / A-Bibliothek bereits vorhanden sein, damit Async / Warten in realen Projekten wirklich praktikabel ist . Für C # haben die meisten ursprünglichen synchronisierten E / A-Funktionen eine alternative Async-Version. Der Grund, warum wir diese Async-Funktionen benötigen, ist, dass in den meisten Fällen Ihr eigener Async / Wait-Code auf eine Async-Methode der Bibliothek hinausläuft.
Die Funktionen der Async-Versionsbibliothek in C # ähneln dem AsynchronousChannel-Konzept in Java. Zum Beispiel haben wir AsynchronousFileChannel.read, das entweder eine Zukunft zurückgeben oder einen Rückruf ausführen kann, nachdem der Lesevorgang abgeschlossen ist. Aber es ist nicht genau das gleiche. Alle C # Async-Funktionen geben Aufgaben zurück (ähnlich wie Future, aber leistungsfähiger als Future).
Nehmen wir also an, Java unterstützt async / await und wir schreiben folgenden Code:
Dann würde ich mir vorstellen, dass der Compiler den ursprünglichen asynchronen / wartenden Code in so etwas umwandelt:
Und hier ist die Implementierung für AsyncHandler:
quelle
In Java gibt es auf Sprachebene kein Äquivalent zu C # async / await. Ein Konzept, das als Fibers aka Cooperative Threads aka Lightweight Threads bekannt ist, könnte eine interessante Alternative sein. Sie finden Java-Bibliotheken, die Fasern unterstützen.
Java-Bibliotheken, die Fasern implementieren
Sie können diesen Artikel (von Quasar) lesen, um eine schöne Einführung in Fasern zu erhalten. Es behandelt, was Threads sind, wie Fasern in der JVM implementiert werden können und enthält einen Quasar-spezifischen Code.
quelle
Task
Klasse) verwendet, indem sie einen Rückruf registriert.Wie bereits erwähnt, gibt es kein direktes Äquivalent, aber mit Java-Bytecode-Modifikationen könnte eine sehr enge Annäherung erstellt werden (sowohl für asynchrone / warteähnliche Anweisungen als auch für die zugrunde liegende Fortsetzung der Implementierung).
Ich arbeite gerade an einem Projekt, das async / await über der JavaFlow-Fortsetzungsbibliothek implementiert. Überprüfen Sie dies bitte https://github.com/vsilaev/java-async-await
Es wurde noch kein Maven-Mojo erstellt, aber Sie können Beispiele mit dem mitgelieferten Java-Agenten ausführen. So sieht asynchroner / wartender Code aus:
@async ist die Annotation, die eine Methode als asynchron ausführbare Datei kennzeichnet. await () ist eine Funktion, die auf CompletableFuture mit Fortsetzungen wartet, und ein Aufruf von "asyncResult (someValue) zurückgeben" beendet die zugehörige CompletableFuture / Continuation
Wie bei C # bleibt der Kontrollfluss erhalten und die Ausnahmebehandlung kann regelmäßig erfolgen (try / catch wie bei sequentiell ausgeführtem Code).
quelle
Java selbst hat keine entsprechenden Funktionen, es gibt jedoch Bibliotheken von Drittanbietern, die ähnliche Funktionen bieten, z . B. Kilim .
quelle
Verstehe zuerst, was Async / Warten ist. Auf diese Weise kann eine Single-Threaded-GUI-Anwendung oder ein effizienter Server mehrere "Fasern" oder "Co-Routinen" oder "Lightweight-Threads" auf einem einzelnen Thread ausführen.
Wenn Sie mit der Verwendung gewöhnlicher Threads einverstanden sind, lautet das Java-Äquivalent
ExecutorService.submit
undFuture.get
. Dies wird blockiert, bis die Aufgabe abgeschlossen ist, und das Ergebnis zurückgegeben. In der Zwischenzeit können andere Threads funktionieren.Wenn Sie den Vorteil von Fasern nutzen möchten, benötigen Sie Unterstützung im Container (ich meine in der GUI-Ereignisschleife oder im Server-HTTP-Anforderungshandler) oder indem Sie Ihren eigenen schreiben.
Servlet 3.0 bietet beispielsweise eine asynchrone Verarbeitung. JavaFX bietet
javafx.concurrent.Task
. Diese haben jedoch nicht die Eleganz von Sprachmerkmalen. Sie arbeiten mit gewöhnlichen Rückrufen.quelle
In Java gibt es nichts Natives, mit dem Sie dies wie asynchrone / wartende Schlüsselwörter tun können. Wenn Sie jedoch wirklich möchten, können Sie einen CountDownLatch verwenden . Du könntest dann asynchron / warten imitieren, indem Sie dies weitergeben (zumindest in Java7). Dies ist eine gängige Praxis beim Testen von Android-Einheiten, bei denen wir einen asynchronen Aufruf tätigen müssen (normalerweise eine von einem Handler gepostete ausführbare Datei) und dann auf das Ergebnis warten müssen (Countdown).
Dies jedoch in Ihrer Anwendung im Gegensatz zu Ihrem Test zu verwenden, ist NICHT das, was ich empfehle. Das wäre extrem schlecht, da CountDownLatch davon abhängt, dass Sie effektiv die richtige Anzahl von Malen und an den richtigen Stellen herunterzählen.
quelle
Ich mache und veröffentlichte Java async / await Bibliothek. https://github.com/stofu1234/kamaitachi
Diese Bibliothek benötigt keine Compiler-Erweiterung und realisiert eine stapellose E / A-Verarbeitung in Java.
↓
quelle
Java hat leider kein Äquivalent zu async / await. Das nächste, was Sie erreichen können, ist wahrscheinlich mit ListenableFuture von Guava und Listener-Verkettung, aber es wäre immer noch sehr umständlich, für Fälle mit mehreren asynchronen Aufrufen zu schreiben, da die Verschachtelungsebene sehr schnell zunehmen würde.
Wenn Sie eine andere Sprache als JVM verwenden möchten, gibt es in Scala glücklicherweise Async / Warten, ein direktes C # Async / Warten-Äquivalent mit einer nahezu identischen Syntax und Semantik: https://github.com/scala/ async /
Beachten Sie, dass diese Funktionalität zwar eine ziemlich erweiterte Compiler-Unterstützung in C # benötigt, in Scala jedoch dank eines sehr leistungsfähigen Makrosystems in Scala als Bibliothek hinzugefügt werden kann und daher auch älteren Versionen von Scala wie 2.10 hinzugefügt werden kann. Zusätzlich ist Scala klassenkompatibel mit Java, sodass Sie den asynchronen Code in Scala schreiben und ihn dann von Java aus aufrufen können.
Es gibt auch ein anderes ähnliches Projekt namens Akka Dataflow http://doc.akka.io/docs/akka/2.3-M1/scala/dataflow.html , das unterschiedliche Formulierungen verwendet, aber konzeptionell sehr ähnlich ist, jedoch mit begrenzten Fortsetzungen und nicht mit Makros implementiert wird (So funktioniert es auch mit älteren Scala-Versionen wie 2.9).
quelle
Java hat kein direktes Äquivalent zur C # -Sprachenfunktion namens async / await, es gibt jedoch einen anderen Ansatz für das Problem, das async / await zu lösen versucht. Es heißt Projekt Loom und bietet virtuelle Threads für die Parallelität mit hohem Durchsatz. Es wird in einer zukünftigen Version von OpenJDK verfügbar sein.
Dieser Ansatz löst auch das " Problem der farbigen Funktion ", das Async / Warten hat.
Ähnliches gilt auch für Golang ( Goroutinen ).
quelle
Wenn Sie nur nach sauberem Code suchen, der den gleichen Effekt wie async / await in Java simuliert, und es Ihnen nichts ausmacht, den aufgerufenen Thread zu blockieren, bis er abgeschlossen ist, z. B. in einem Test, können Sie Folgendes verwenden:
quelle
Die AsynHelper- Java-Bibliothek enthält eine Reihe von Dienstprogrammklassen / -methoden für solche asynchronen Aufrufe (und Wartezeiten).
Wenn eine Reihe von Methodenaufrufen oder Codeblöcken asynchron ausgeführt werden soll, enthält es eine nützliche Hilfsmethode AsyncTask .submitTasks wie im folgenden Snippet.
Wenn gewartet werden soll, bis alle asynchronen Codes vollständig ausgeführt wurden, kann die Variable AsyncTask.submitTasksAndWait verwendet werden.
Wenn ein Rückgabewert von jedem asynchronen Methodenaufruf oder Codeblock abgerufen werden soll, kann der AsyncSupplier .submitSuppliers verwendet werden, sodass das Ergebnis von dem von der Methode zurückgegebenen Array der Ergebnislieferanten abgerufen werden kann. Unten ist das Beispiel-Snippet:
Wenn sich der Rückgabetyp jeder Methode unterscheidet, verwenden Sie die folgende Art von Snippet.
Das Ergebnis der asynchronen Methodenaufrufe / Codeblöcke kann auch an einem anderen Codepunkt im selben Thread oder an einem anderen Thread wie im folgenden Snippet abgerufen werden.
quelle