Java 等效于 C# async/await?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16539245/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 01:17:28  来源:igfitidea点击:

Java Equivalent of C# async/await?

c#java

提问by user960567

I am a normal C# developer but occasionally I develop application in Java. I'm wondering if there is any Java equivalent of C# async/await? In simple words what is the java equivalent of:

我是一名普通的 C# 开发人员,但偶尔我会用 Java 开发应用程序。我想知道是否有任何 Java 等价于 C# async/await?简而言之,java相当于什么:

async Task<int> AccessTheWebAsync()
{ 
    HttpClient client = new HttpClient();
    var urlContents = await client.GetStringAsync("http://msdn.microsoft.com");
    return urlContents.Length;
}

采纳答案by Jon Skeet

No, there isn't any equivalent of async/await in Java - or even in C# before v5.

不,在 Java 中没有任何等效的 async/await - 甚至在 v5 之前的 C# 中。

It's a fairly complex language feature to build a state machine behind the scenes.

在幕后构建状态机是一个相当复杂的语言功能。

There's relatively little languagesupport for asynchrony/concurrency in Java, but the java.util.concurrentpackage contains a lot of useful classesaround this. (Not quite equivalent to the Task Parallel Library, but the closest approximation to it.)

Java 中对异步/并发的语言支持相对较少,但该java.util.concurrent包包含许多围绕此的有用。(不完全等同于任务并行库,但最接近它。)

回答by Alexei Kaigorodov

Java itself has no equivalent features, but third-party libraries exist which offer similar functionality, e.g.Kilim.

Java 本身没有等效的功能,但存在提供类似功能的第三方库,例如Kilim

回答by stevebot

There isn't anything native to java that lets you do this like async/await keywords, but what you can do if you really want to is use a CountDownLatch. You couldthen imitate async/await by passing this around (at least in Java7). This is a common practice in Android unit testing where we have to make an async call (usually a runnable posted by a handler), and then await for the result (count down).

没有任何 Java 原生的东西可以让您像 async/await 关键字那样执行此操作,但是如果您真的想要,您可以使用CountDownLatch。然后你可以通过传递它来模仿 async/await(至少在 Java7 中)。这是 Android 单元测试中的常见做法,我们必须进行异步调用(通常是由处理程序发布的可运行对象),然后等待结果(倒计时)。

Using this however inside your application as opposed to your test is NOTwhat I am recommending. That would be extremely shoddy as CountDownLatch depends on you effectively counting down the right number of times and in the right places.

然而,在你的应用程序中使用它而不是你的测试并不是我推荐的。这将是非常粗制滥造的,因为 CountDownLatch 取决于您在正确的位置有效地倒计时正确的次数。

回答by Aleksandr Dubinsky

First, understand what async/await is. It is a way for a single-threaded GUI application or an efficient server to run multiple "fibers" or "co-routines" or "lightweight threads" on a single thread.

首先,了解什么是 async/await。它是单线程 GUI 应用程序或高效服务器在单个线程上运行多个“纤程”或“协程”或“轻量级线程”的一种方式。

If you are ok with using ordinary threads, then the Java equivalent is ExecutorService.submitand Future.get. This will block until the task completes, and return the result. Meanwhile, other threads can do work.

如果您可以使用普通线程,那么 Java 等价物是ExecutorService.submitFuture.get。这将阻塞直到任务完成,并返回结果。同时,其他线程可以工作。

If you want the benefit of something like fibers, you need support in the container (I mean in the GUI event loop or in the server HTTP request handler), or by writing your own.

如果您想获得纤程之类的好处,您需要容器中的支持(我的意思是在 GUI 事件循环或服务器 HTTP 请求处理程序中),或者通过编写自己的。

For example, Servlet 3.0 offers asynchronous processing. JavaFX offers javafx.concurrent.Task. These don't have the elegance of language features, though. They work through ordinary callbacks.

例如,Servlet 3.0 提供异步处理。JavaFX 提供javafx.concurrent.Task. 但是,这些没有语言功能的优雅。它们通过普通回调工作。

回答by FabienB

There is no equivalent of C# async/await in Java at the language level. A concept known as Fibersaka cooperative threadsaka lightweight threadscould be an interesting alternative. You can find Java libraries providing support for fibers.

在语言级别,Java 中没有等效的 C# async/await。一个被称为Fibersaka协作线程aka轻量级线程的概念可能是一个有趣的替代方案。您可以找到为纤程提供支持的 Java 库。

Java libraries implementing Fibers

实现 Fibers 的 Java 库

You can read this article (from Quasar)for a nice introduction to fibers. It covers what threads are, how fibers can be implemented on the JVM and has some Quasar specific code.

您可以阅读这篇文章(来自 Quasar),以获得对纤维的一个很好的介绍。它涵盖了线程是什么,纤维如何在 JVM 上实现,并有一些 Quasar 特定的代码。

回答by caisx25

asyncand awaitare syntactic sugars. The essence of async and await is state machine. The compiler will transform your async/await code into a state machine.

asyncawait是语法糖。async 和 await 的本质是状态机。编译器会将您的 async/await 代码转换为状态机。

At the same time, in order for async/await to be really practicable in real projects, we need to have lots of Async I/O library functionsalready in place. For C#, most original synchronized I/O functions has an alternative Async version. The reason we need these Async functions is because in most cases, your own async/await code will boil down to some library Async method.

同时,为了让 async/await 在实际项目中真正实用,我们需要已经准备好大量的Async I/O 库函数。对于 C#,大多数原始同步 I/O 函数都有一个替代的异步版本。我们需要这些 Async 函数的原因是因为在大多数情况下,您自己的 async/await 代码将归结为某个库 Async 方法。

The Async version library functions in C# is kind of like the AsynchronousChannel concept in Java. For example, we have AsynchronousFileChannel.read which can either return a Future or execute a callback after the read operation is done. But it's not exactly the same. All C# Async functions return Tasks (similar to Future but more powerful than Future).

C# 中的 Async 版本库函数有点类似于 Java 中的 AsynchronousChannel 概念。例如,我们有 AsynchronousFileChannel.read,它可以在读取操作完成后返回 Future 或执行回调。但这并不完全相同。所有 C# 异步函数都返回任务(类似于 Future 但比 Future 更强大)。

So let's say Java do support async/await, and we write some code like this:

所以假设 Java 确实支持 async/await,我们会写一些这样的代码:

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);
}

Then I would imagine the compiler will transform the original async/await code into something like this:

然后我会想象编译器会将原始的 async/await 代码转换成这样的:

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;
}

And here is the implementation for AsyncHandler:

这是 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);
    }
}

回答by Miguel Gamboa

The awaituses a continuation to execute additional code when the asynchronous operation completes (client.GetStringAsync(...)).

所述await使用的延续当异步操作完成(以执行额外的代码client.GetStringAsync(...))。

So, as the most close approximation I would use a CompletableFuture<T>(the Java 8 equivalent to .net Task<TResult>) based solution to process the Http request asynchronously.

因此,作为最接近的近似值,我将使用基于CompletableFuture<T>(Java 8 相当于 .net Task<TResult>)的解决方案来异步处理 Http 请求。

UPDATED on 25-05-2016 to AsyncHttpClientv.2 released on Abril 13th of 2016:

25-05-2016 更新到2016 年 4 月 13 日发布的AsyncHttpClientv.2:

So the Java 8 equivalent to the OP example of AccessTheWebAsync()is the following:

因此,相当于 OP 示例的 Java 8AccessTheWebAsync()如下:

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

This usage was taken from the answer to How do I get a CompletableFuture from an Async Http Client request?and which is according to the new API provided in version 2 of AsyncHttpClientreleased on Abril 13th of 2016, that has already intrinsic support for CompletableFuture<T>.

此用法取自如何从异步 Http 客户端请求中获取 CompletableFuture的答案根据2016 年 4 月 13 日发布的AsyncHttpClient版本 2 中提供的新 API,该 API已经对CompletableFuture<T>.

Original answer using version 1 of AsyncHttpClient:

使用 AsyncHttpClient 版本 1 的原始答案:

To that end we have two possible approaches:

为此,我们有两种可能的方法:

  • the first one uses non-blocking IO and I call it AccessTheWebAsyncNio. Yet, because the AsyncCompletionHandleris an abstract class (instead of a functional interface) we cannot pass a lambda as argument. So it incurs in inevitable verbosity due to the syntax of anonymous classes. However, this solution is the most close to the execution flow of the given C# example.

  • the second one is slightly less verbose however it will submit a new Taskthat ultimately will block a thread on f.get()until the response is complete.

  • 第一个使用非阻塞 IO,我称之为AccessTheWebAsyncNio. 然而,因为AsyncCompletionHandler是一个抽象类(而不是函数式接口),所以我们不能将 lambda 作为参数传递。因此,由于匿名类的语法,它不可避免地会导致冗长。但是,此解决方案最接近给定 C# 示例的执行流程

  • 第二个稍微不那么冗长,但是它会提交一个新任务,最终会阻塞一个线程,f.get()直到响应完成。

First approach, more verbose but non-blocking:

第一种方法,更冗长但非阻塞:

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;
}

Second approachless verbose but blocking a 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());
    }
}

回答by stofu

I make and released Java async/await library. https://github.com/stofu1234/kamaitachi

我制作并发布了 Java 异步/等待库。 https://github.com/stofu1234/kamaitachi

This library don't need compiler extension, and realize stackless IO processing in Java.

该库不需要编译器扩展,在Java中实现无栈IO处理。

    async Task<int> AccessTheWebAsync(){ 
        HttpClient client= new HttpClient();
        var urlContents= await client.GetStringAsync("http://msdn.microsoft.com");
       return urlContents.Length;
    }

   ↓

   ↓

    //LikeWebApplicationTester.java
    BlockingQueue<Integer> AccessTheWebAsync() {
       HttpClient client = new HttpClient();
       return awaiter.await(
            () -> client.GetStringAsync("http://msdn.microsoft.com"),
            urlContents -> {
                return urlContents.length();
            });
    }
    public void doget(){
        BlockingQueue<Integer> lengthQueue=AccessTheWebAsync();
        awaiter.awaitVoid(()->lengthQueue.take(),
            length->{
                System.out.println("Length:"+length);
            }
            );
    }

回答by Piotr Ko?aczkowski

Java has unfortunately no equivalent of async/await. The closest you can get is probably with ListenableFuture from Guava and listener chaining, but it would be still very cumbersome to write for cases involving multiple asynchronous calls, as the nesting level would very quickly grow.

不幸的是,Java 没有等价于 async/await。您可以获得的最接近的可能是来自 Guava 的 ListenableFuture 和侦听器链接,但是对于涉及多个异步调用的案例编写仍然非常麻烦,因为嵌套级别会非常快地增长。

If you're ok with using a different language on top of JVM, fortunately there is async/await in Scala which is a direct C# async/await equivalent with an almost identical syntax and semantics: https://github.com/scala/async/

如果您可以在 JVM 之上使用不同的语言,幸运的是 Scala 中有 async/await,它是直接的 C# async/await 等效项,具有几乎相同的语法和语义:https: //github.com/scala/异步/

Note that although this functionality needed a pretty advanced compiler support in C#, in Scala it could be added as a library thanks to a very powerful macro system in Scala and therefore can be added even to older versions of Scala like 2.10. Additionally Scala is class-compatible with Java, so you can write the async code in Scala and then call it from Java.

请注意,尽管此功能在 C# 中需要非常高级的编译器支持,但在 Scala 中,由于 Scala 中非常强大的宏系统,它可以作为库添加,因此甚至可以添加到 Scala 的旧版本(如 2.10)中。此外,Scala 与 Java 类兼容,因此您可以在 Scala 中编写异步代码,然后从 Java 中调用它。

There is also another similar project called Akka Dataflow http://doc.akka.io/docs/akka/2.3-M1/scala/dataflow.htmlwhich uses different wording but conceptually is very similar, however implemented using delimited continuations, not macros (so it works with even older Scala versions like 2.9).

还有另一个类似的项目叫做 Akka Dataflow http://doc.akka.io/docs/akka/2.3-M1/scala/dataflow.html它使用不同的措辞但概念上非常相似,但是使用分隔的延续而不是宏来实现(因此它适用于更旧的 Scala 版本,例如 2.9)。

回答by Valery Silaev

As it was mentioned, there is no direct equivalent, but very close approximation could be created with Java bytecode modifications (for both async/await-like instructions and underlying continuations implementation).

正如前面提到的,没有直接的等价物,但是可以通过 Java 字节码修改(对于 async/await 类指令和底层延续实现)创建非常接近的近似值。

I'm working right now on a project that implements async/await on top of JavaFlow continuationlibrary, please check https://github.com/vsilaev/java-async-await

我现在正在开发一个在JavaFlow 延续库之上实现 async/await 的项目,请查看https://github.com/vsilaev/java-async-await

No Maven mojo is created yet, but you may run examples with supplied Java agent. Here is how async/await code looks like:

尚未创建 Maven mojo,但您可以使用提供的 Java 代理运行示例。下面是异步/等待代码的样子:

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 is the annotation that flags a method as asynchronously executable, await() is a function that waits on CompletableFuture using continuations and a call to "return asyncResult(someValue)" is what finalizes associated CompletableFuture/Continuation

@async 是将方法标记为异步可执行的注释,await() 是一个使用延续等待 CompletableFuture 的函数,调用“return asyncResult(someValue)”是最终确定关联的 CompletableFuture/Continuation

As with C#, control flow is preserved and exception handling may be done in regular manner (try/catch like in sequentially executed code)

与 C# 一样,控制流被保留,异常处理可以以常规方式完成(try/catch 就像在顺序执行的代码中一样)