Java-Äquivalent von C# async/await?

Lesezeit: 11 Minuten

Benutzer-Avatar
Imran Qadir Baksh – Baloch

Ich bin ein normaler C#-Entwickler, aber gelegentlich entwickle ich Anwendungen in Java. Ich frage mich, ob es ein Java-Äquivalent zu 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;
}

  • Warum das schön wäre: Rückrufe als Go To Statement unserer Generationen von Miguel de Icaza.

    – andrewdotn

    12. November 2013 um 4:00 Uhr

  • Die aktuelle Lösung von Java besteht darin, sich nicht mit tatsächlichen Werten zu befassen, denen das Präfix vorangestellt ist asyncaber verwenden Future oder Observable Werte statt.

    – SD

    23. Februar 2018 um 4:32 Uhr

  • Es gibt kein Äquivalent. Und es tut weh. Eine weitere fehlende Funktion, für die Sie komplizierte Problemumgehungen und Bibliotheken benötigen, ohne jemals den gleichen Effekt wie diese beiden einfachen Wörter zu erreichen.

    – Spyro

    12. Dezember 2019 um 17:35 Uhr

  • @pieroxy nein async ist kein Multithreading und Python hatte Multithreading lange vor Async. Multithreading verwendet Betriebssystem-Threads und die OS-Zeitscheiben zwischen ihnen. Async verwendet einen einzelnen OS-Thread und die Anwendung übernimmt die Verantwortung, Aufgaben zu wechseln, wenn eine Aufgabe einen logischen Punkt erreicht, an dem sie anhalten muss (z. B. Lesen im Netzwerk). Der springende Punkt bei Async ist, dass es denselben Thread wiederverwendet, um andere Aufgaben auszuführen, während eine Aufgabe blockiert. Das Fehlen von Threading ist eine reine JavaScript-Sache.

    – Philip Couling

    30. August 2021 um 9:00 Uhr


  • @pieroxy immer noch nein. Auch in c# bleibt das Kernkonzept dasselbe und ist kein syntaktischer Zucker (wie von Jon Skeet beschrieben). Sicherlich können mehrere Threads Aufgaben aus demselben Pool ausführen, aber das bedeutet nicht, dass Async ein Threading-Modell ist. Async ist schwer zu verstehen und viele Leute tun es nicht. In allen Sprachen, die Async unterstützen; await kann den gesamten Aufrufstapel der Aufgabe aussetzen und etwas anderes im selben Thread ausführen. In Java können Sie den Stack einfach nicht anhalten und später wiederherstellen.

    – Philip Couling

    30. August 2021 um 10:33 Uhr


Nein, es gibt kein Äquivalent zu async/await in Java – oder sogar in C# vor v5.

Es ist ein ziemlich komplexes Sprachfeature, um hinter den Kulissen eine Zustandsmaschine zu erstellen.

Es gibt relativ wenig Sprache Unterstützung für Asynchronität/Parallelität in Java, aber die java.util.concurrent Paket enthält viele nützliche Klassen um diese herum. (Nicht ganz gleichwertig mit der Task Parallel Library, aber die nächste Annäherung daran.)

  • @ user960567: Nein, mein Punkt ist, dass es a ist Sprache Feature – es kann nicht nur in Bibliotheken gestellt werden. Ich glaube nicht, dass zumindest für Java 8 ein Äquivalent geplant ist.

    – Jon Skeet

    14. Mai 2013 um 9:23 Uhr


  • @user960567: Sie müssen zwischen der Version von C#, die Sie verwenden, und der Version von .NET, die Sie verwenden, unterscheiden. async/await ist a Sprache Feature – es wurde in C# 5 eingeführt. Ja, Sie können Microsoft.Bcl.Async verwenden, um async/await auf .NET 4 abzuzielen, aber Sie müssen immer noch einen C# 5-Compiler verwenden.

    – Jon Skeet

    14. Mai 2013 um 9:31 Uhr

  • @rozar: Nein, nicht wirklich. Es gibt bereits mehrere Optionen für Asynchronität – aber RxJava ändert nichts daran Sprache so wie es C# getan hat. Ich habe nichts gegen Rx, aber es ist nicht dasselbe wie async in C# 5.

    – Jon Skeet

    26. März 2014 um 6:46 Uhr

  • @DtechNet: Nun, es gibt viele JVM-Maschinen, die asynchron sind, ja … das unterscheidet sich sehr von denen, die es gibt eigentliche Sprachmerkmale unterstützt jedoch Asynchronität. (Es gab auch viel Asynchronität in .NET vor async/await … aber async/await macht es weit leichter ausnutzen.)

    – Jon Skeet

    21. Oktober 2015 um 5:45 Uhr


  • @Aarkon: Ich würde das argumentieren, es sei denn, es ist explizit Sprache Support, die Antwort ist immer noch richtig. Es geht nicht nur um Bibliotheken, die das Scheduling vereinfachen – hier ist die ganze Art und Weise wichtig, wie der C#-Compiler einen Zustandsautomaten aufbaut.

    – Jon Skeet

    11. Juni 2019 um 11:09 Uhr

Benutzer-Avatar
Miguel Gamboa

Das await verwendet eine Fortsetzung, um zusätzlichen Code auszuführen, wenn der asynchrone Vorgang abgeschlossen ist (client.GetStringAsync(...)).

Als beste Annäherung würde ich also a verwenden CompletableFuture<T> (das Java 8-Äquivalent zu .net Task<TResult>)-basierte Lösung, um die Http-Anfrage asynchron zu verarbeiten.

AKTUALISIERT am 25.05.2016 zu AsyncHttpClient v.2 veröffentlicht am 13. April 2016:

Also das Java 8-Äquivalent zum OP-Beispiel von AccessTheWebAsync() ist das Folgende:

CompletableFuture<Integer> AccessTheWebAsync()
{
    AsyncHttpClient asyncHttpClient = new DefaultAsyncHttpClient();
    return asyncHttpClient
       .prepareGet("http://msdn.microsoft.com")
       .execute()
       .toCompletableFuture()
       .thenApply(Response::getResponseBody)
       .thenApply(String::length);
}

Diese Verwendung wurde aus der Antwort auf How do I get a CompletableFuture from a Async Http Client request entnommen? und die gemäß der neuen API in Version 2 von bereitgestellt wird AsyncHttpClient veröffentlicht am 13. April 2016, das bereits intrinsische Unterstützung für hat CompletableFuture<T>.

Ursprüngliche Antwort mit Version 1 von AsyncHttpClient:

Dazu haben wir zwei mögliche Vorgehensweisen:

  • Der erste verwendet nicht blockierendes IO und ich nenne es AccessTheWebAsyncNio. Doch weil die AsyncCompletionHandler eine abstrakte Klasse ist (statt einer funktionalen Schnittstelle), können wir kein Lambda als Argument übergeben. Daher kommt es aufgrund der Syntax anonymer Klassen zu einer unvermeidlichen Ausführlichkeit. Jedoch, Diese Lösung kommt dem Ausführungsablauf des angegebenen C#-Beispiels am nächsten.

  • Die zweite ist etwas weniger ausführlich, wird jedoch eine neue einreichen Aufgabe das wird letztendlich einen Thread blockieren f.get() bis die Antwort vollständig ist.

Erste Ansatzausführlicher, aber nicht blockierend:

static CompletableFuture<Integer> AccessTheWebAsyncNio(){
    final AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
    final CompletableFuture<Integer> promise = new CompletableFuture<>();
    asyncHttpClient
        .prepareGet("https://msdn.microsoft.com")
        .execute(new AsyncCompletionHandler<Response>(){
            @Override
            public Response onCompleted(Response resp) throws Exception {
                promise.complete(resp.getResponseBody().length());
                return resp;
            }
        });
    return promise;
}

Zweiter Ansatz weniger ausführlich, aber blockiert einen Thread:

static CompletableFuture<Integer> AccessTheWebAsync(){
    try(AsyncHttpClient asyncHttpClient = new AsyncHttpClient()){
        Future<Response> f = asyncHttpClient
            .prepareGet("https://msdn.microsoft.com")
            .execute();
        return CompletableFuture.supplyAsync(
            () -> return f.join().getResponseBody().length());
    }
}

  • Eigentlich ist das das Äquivalent zum Happy Flow. Die Behandlung von Ausnahmen, final und anderen wird nicht behandelt. Wenn Sie sie einschließen, wird der Code viel komplexer und fehleranfälliger.

    – hamb

    16. Januar 2019 um 6:20 Uhr


  • Das ist keine Fortsetzung. Dieses Beispiel verfehlt den eigentlichen Zweck von async/await, der darin besteht, den aktuellen Thread freizugeben, um andere Dinge auszuführen, und dann die Ausführung dieser Methode im aktuellen Thread fortzusetzen, nachdem eine Antwort eintrifft. (Dies ist entweder erforderlich, damit der UI-Thread reagiert, oder um die Speichernutzung zu reduzieren.) Was dieses Beispiel bewirkt, ist eine einfache Blockierungs-Thread-Synchronisierung plus einige Callbacks.

    – Aleksandr Dubinsky

    12. November 2019 um 21:52 Uhr

  • @AleksandrDubinsky Ich stimme Ihnen zu, wenn Sie darauf hinweisen, dass der Rückruf möglicherweise nicht im Aufrufer-Thread ausgeführt wird. Sie haben Recht. Ich bin nicht einverstanden damit, einen Thread zu blockieren. Meine aktualisierte Antwort von AKTUALISIERT am 25.05.2016 ist nicht blockierend.

    – Miguel Gamboa

    13. November 2019 um 13:37 Uhr

  • …. und dieses Beispiel ist genau der Grund, warum C# beim asynchronen Arbeiten so viel einfacher zu schreiben und zu lesen ist. Es ist nur ein Schmerz in Java.

    – Spyro

    12. Dezember 2019 um 17:37 Uhr

Kasse ea-async was Java-Bytecode umschreibt, um async/await ziemlich gut zu simulieren. Laut ihrer Readme: “Es ist stark von Async-Await auf der .NET CLR inspiriert”

  • Verwendet es jemand in der Produktion?

    – Herr Wang von Nebenan

    22. Dezember 2016 um 1:54 Uhr

  • Es scheint, dass EA das tut, ich glaube nicht, dass sie Geld für etwas ausgeben würden, das nicht für die Produktion geeignet ist.

    – B. Medeiros

    21. August 2017 um 10:23 Uhr

  • Es ist ziemlich normal, Geld für etwas auszugeben und dann zu entscheiden, dass es nicht für die Produktion geeignet ist; nur so lernt man. Es ist möglich, es ohne Java-Agent-Einstellungen in der Produktion zu verwenden; das sollte die Messlatte ein wenig senken (github.com/electronicarts/ea-async).

    – Thoredge

    23. Mai 2018 um 7:49 Uhr

asynchron und erwarten sind syntaktische Zucker. Die Essenz von async und await ist eine Zustandsmaschine. Der Compiler wandelt Ihren async/await-Code in einen Zustandsautomaten um.

Damit async/await in realen Projekten wirklich praktikabel ist, müssen wir gleichzeitig viele haben Asynchrone E/A-Bibliotheksfunktionen Bereits vorhanden. Für C# haben die meisten ursprünglichen synchronisierten I/O-Funktionen eine alternative Async-Version. Der Grund, warum wir diese Async-Funktionen benötigen, liegt darin, dass Ihr eigener Async/Await-Code in den meisten Fällen auf eine Async-Methode der Bibliothek hinausläuft.

Die Bibliotheksfunktionen der Async-Version in C# ähneln dem AsynchronousChannel-Konzept in Java. Zum Beispiel haben wir AsynchronousFileChannel.read, das entweder ein Future zurückgeben oder einen Rückruf ausführen kann, nachdem der Lesevorgang abgeschlossen ist. Aber es ist nicht genau dasselbe. Alle asynchronen C#-Funktionen geben Tasks zurück (ähnlich wie Future, aber leistungsfähiger als Future).

Nehmen wir also an, Java unterstützt async/await, und wir schreiben Code wie diesen:

public static async Future<Byte> readFirstByteAsync(String filePath) {
    Path path = Paths.get(filePath);
    AsynchronousFileChannel channel = AsynchronousFileChannel.open(path);

    ByteBuffer buffer = ByteBuffer.allocate(100_000);
    await channel.read(buffer, 0, buffer, this);
    return buffer.get(0);
}

Dann würde ich mir vorstellen, dass der Compiler den ursprünglichen async/await-Code in so etwas umwandelt:

public static Future<Byte> readFirstByteAsync(String filePath) {

    CompletableFuture<Byte> result = new CompletableFuture<Byte>();

    AsyncHandler ah = new AsyncHandler(result, filePath);

    ah.completed(null, null);

    return result;
}

Und hier ist die Implementierung für AsyncHandler:

class AsyncHandler implements CompletionHandler<Integer, ByteBuffer>
{
    CompletableFuture<Byte> future;
    int state;
    String filePath;

    public AsyncHandler(CompletableFuture<Byte> future, String filePath)
    {
        this.future = future;
        this.state = 0;
        this.filePath = filePath;
    }

    @Override
    public void completed(Integer arg0, ByteBuffer arg1) {
        try {
            if (state == 0) {
                state = 1;
                Path path = Paths.get(filePath);
                AsynchronousFileChannel channel = AsynchronousFileChannel.open(path);

                ByteBuffer buffer = ByteBuffer.allocate(100_000);
                channel.read(buffer, 0, buffer, this);
                return;
            } else {
                Byte ret = arg1.get(0);
                future.complete(ret);
            }

        } catch (Exception e) {
            future.completeExceptionally(e);
        }
    }

    @Override
    public void failed(Throwable arg0, ByteBuffer arg1) {
        future.completeExceptionally(arg0);
    }
}

Benutzer-Avatar
FabienB

Auf Sprachebene gibt es in Java kein Äquivalent zu C# async/await. Ein Konzept, bekannt als Fasern auch bekannt kooperative Fäden auch bekannt leichte Fäden könnte eine interessante Alternative sein. Sie finden Java-Bibliotheken, die Glasfasern unterstützen.

Java-Bibliotheken, die Fibers implementieren

Du kannst lesen dieser Artikel (von Quasar) für eine schöne Einführung in Fasern. Es behandelt, was Threads sind, wie Fibers auf der JVM implementiert werden können und enthält einen Quasar-spezifischen Code.

  • async/await in C# ist kein Fiber. Es ist nur Compiler-Magie, die die Fortsetzung von Promise verwendet (die Task Klasse) durch Registrieren eines Rückrufs.

    – UltimaWaffe

    27. Juni 2016 um 5:59 Uhr

  • @UltimaWeapon Also, was betrachtest du als Fasern?

    – Aleksandr Dubinsky

    14. Dezember 2018 um 16:09 Uhr

  • @AleksandrDubinsky Eines der Beispiele ist goroutine.

    – UltimaWaffe

    15. Dezember 2018 um 10:19 Uhr

  • @UltimaWeapon Ich suchte nach einer Erklärung.

    – Aleksandr Dubinsky

    16. Dezember 2018 um 8:36 Uhr

  • @AleksandrDubinsky Ich bin faul, es zu erklären. Wenn Sie es wirklich wissen wollen, können Sie den Artikel unter der Haube von Goroutine durchsuchen.

    – UltimaWaffe

    16. Dezember 2018 um 15:05 Uhr

Benutzer-Avatar
Valery Silaev

Wie bereits erwähnt, gibt es kein direktes Äquivalent, aber eine sehr gute Annäherung könnte mit Java-Bytecode-Modifikationen erstellt werden (sowohl für async/await-ähnliche Anweisungen als auch für die zugrunde liegende Fortsetzungsimplementierung).

Ich arbeite gerade an einem Projekt, das async/await zusätzlich implementiert JavaFlow-Fortsetzung Bibliothek, bitte prüfen 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 async/await-Code aus:

public class AsyncAwaitNioFileChannelDemo {

public static void main(final String[] argv) throws Exception {

    ...
    final AsyncAwaitNioFileChannelDemo demo = new AsyncAwaitNioFileChannelDemo();
    final CompletionStage<String> result = demo.processFile("./.project");
    System.out.println("Returned to caller " + LocalTime.now());
    ...
}


public @async CompletionStage<String> processFile(final String fileName) throws IOException {
    final Path path = Paths.get(new File(fileName).toURI());
    try (
            final AsyncFileChannel file = new AsyncFileChannel(
                path, Collections.singleton(StandardOpenOption.READ), null
            );              
            final FileLock lock = await(file.lockAll(true))
        ) {

        System.out.println("In process, shared lock: " + lock);
        final ByteBuffer buffer = ByteBuffer.allocateDirect((int)file.size());

        await( file.read(buffer, 0L) );
        System.out.println("In process, bytes read: " + buffer);
        buffer.rewind();

        final String result = processBytes(buffer);

        return asyncResult(result);

    } catch (final IOException ex) {
        ex.printStackTrace(System.out);
        throw ex;
    }
}

@async ist die Anmerkung, die eine Methode als asynchron ausführbar kennzeichnet, await() ist eine Funktion, die mit Fortsetzungen auf CompletableFuture wartet, und ein Aufruf von „return asyncResult(someValue)“ beendet die zugehörige CompletableFuture/Continuation

Wie bei C# bleibt die Ablaufsteuerung erhalten und die Ausnahmebehandlung kann auf reguläre Weise erfolgen (try/catch wie in sequentiell ausgeführtem Code).

  • async/await in C# ist kein Fiber. Es ist nur Compiler-Magie, die die Fortsetzung von Promise verwendet (die Task Klasse) durch Registrieren eines Rückrufs.

    – UltimaWaffe

    27. Juni 2016 um 5:59 Uhr

  • @UltimaWeapon Also, was betrachtest du als Fasern?

    – Aleksandr Dubinsky

    14. Dezember 2018 um 16:09 Uhr

  • @AleksandrDubinsky Eines der Beispiele ist Goroutine.

    – UltimaWaffe

    15. Dezember 2018 um 10:19 Uhr

  • @UltimaWeapon Ich suchte nach einer Erklärung.

    – Aleksandr Dubinsky

    16. Dezember 2018 um 8:36 Uhr

  • @AleksandrDubinsky Ich bin faul, es zu erklären. Wenn Sie es wirklich wissen wollen, können Sie den Artikel unter der Haube von Goroutine durchsuchen.

    – UltimaWaffe

    16. Dezember 2018 um 15:05 Uhr

Benutzer-Avatar
Alexei Kaigorodow

Java selbst hat keine gleichwertigen Funktionen, aber es gibt Bibliotheken von Drittanbietern, die ähnliche Funktionen bieten, zKelim.

  • Ich glaube nicht, dass diese Bibliothek etwas mit dem zu tun hat, was async/await tut.

    – Natan

    29. August 2014 um 13:05 Uhr

1351570cookie-checkJava-Äquivalent von C# async/await?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy