read Java Equivalent C#async/await?




epplus excel c# (10)

C # async / await сопоставим с понятием, известным как Fibers или кооперативные потоки, или легкие потоки . Нет эквивалента C # async / await в Java на уровне языка, но вы можете найти библиотеки, поддерживающие волокна.

Java-библиотеки, реализующие волокна

Вы можете прочитать эту статью (от Quasar) за хорошее введение в волокна. Он охватывает те потоки, как волокна могут быть реализованы на JVM и имеет определенный код Quasar.

https://code.i-harness.com

Я обычный разработчик C #, но иногда я разрабатываю приложение в Java. Я ищу, есть ли какой-либо Java-эквивалент C # async / wait? Простыми словами, что является эквивалентом java,

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

Java имеет класс java.util.concurrent.Future который эквивалентен классу Task C #.

Вы можете запустить работу над объектом java.util.concurrent.Executor . Существует много реализаций, но ForkJoinTask.fork() стоит посмотреть, если вы ForkJoinTask.fork() как только попробуете это.

Когда вы начнете работу, вам дадут Future . Ваш метод продолжит работу. Когда вам нужен результат из вашего будущего, вы вызываете get() и он будет блокироваться до тех пор, пока результат не будет готов. Это похоже на использование ключевого слова await в C #.


Во-первых, поймите, что такое async / await. Это способ однопоточного приложения GUI или эффективного сервера для запуска нескольких «волокон» или «со-подпрограмм» или «легких потоков» в одном потоке.

Если вы используете обычные потоки, то эквивалент Java - это ExecutorService.submit и Future.get . Это будет блокироваться до завершения задачи и вернуть результат. Между тем, другие потоки могут работать.

Если вы хотите получить что-то вроде волокон, вам нужна поддержка в контейнере (я имею в виду в цикле событий GUI или в обработчике запросов HTTP-сервера), или напишите свой собственный. Например, Servlet 3.0 предлагает асинхронную обработку. JavaFX предлагает javafx.concurrent.Task . Тем не менее, у них нет элегантности языковых функций. Они работают через обычные обратные вызовы.


Если вы просто после чистого кода, который имитирует тот же эффект, что и async / await в java, и не против блокировать поток, который он вызывается до тех пор, пока он не будет завершен, например, в тесте, вы можете использовать что-то вроде этого кода:

interface Async {
    void run(Runnable handler);
}

static void await(Async async) throws InterruptedException {

    final CountDownLatch countDownLatch = new CountDownLatch(1);
    async.run(new Runnable() {

        @Override
        public void run() {
            countDownLatch.countDown();
        }
    });
    countDownLatch.await(YOUR_TIMEOUT_VALUE_IN_SECONDS, TimeUnit.SECONDS);
}

    await(new Async() {
        @Override
        public void run(final Runnable handler) {
            yourAsyncMethod(new CompletionHandler() {

                @Override
                public void completion() {
                    handler.run();
                }
            });
        }
    });

Как уже упоминалось, прямого эквивалента нет, но очень близкое приближение может быть создано с помощью модификаций байт-кода Java (для команд async / await-like и реализации последующих продолжений).

Я сейчас работаю над проектом, который реализует async / wait поверх библиотеки продолжения JavaFlow , проверьте https://github.com/vsilaev/java-async-await

Пока нет Maven mojo, но вы можете запускать примеры с предоставленным Java-агентом. Вот как выглядит код async / await:

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 - это аннотация, которая помещает метод как асинхронно исполняемый, await () - это функция, которая ждет на CompletableFuture с продолжением, а вызов «return asyncResult (someValue)» - это то, что завершает ассоциированный CompletableFuture / Continuation

Как и в случае с C #, поток управления сохраняется, и обработка исключений может выполняться обычным образом (try / catch, как в последовательно исполняемом коде)


Нет, нет эквивалента async / await в Java - или даже в C # перед v5.

Это довольно сложная языковая функция для создания конечной машины за кулисами.

В Java существует относительно небольшая языковая поддержка для асинхронности / параллелизма, но пакет java.util.concurrent содержит много полезных классов . (Не совсем эквивалентно параллельной библиотеке задач, но ближе всего к ней).


Сама Java не имеет эквивалентных функций, но существуют сторонние библиотеки, которые предлагают аналогичную функциональность, например Kilim .


Я создаю и освобождаю Java async / wait. https://github.com/stofu1234/kamaitachi

Эта библиотека не нуждается в расширении компилятора и реализует многоуровневую обработку ввода-вывода в Java.

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

await использует продолжение для выполнения дополнительного кода при завершении асинхронной операции ( client.GetStringAsync(...) ).

Таким образом, в качестве самого близкого приближения я использовал бы приложение CompletableFuture<T> (эквивалентное Java 8 для .NET- Task<TResult> ) для обработки запроса Http асинхронно.

ОБНОВЛЕНО 25-05-2016 к AsyncHttpClient v.2, выпущенному на Abril 13th 2016:

Таким образом, Java 8, эквивалентный OP-примеру AccessTheWebAsync() выглядит следующим образом:

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

Это использование было взято из ответа на вопрос: Как мне получить CompletableFuture из запроса клиента Async Http? и который соответствует новому API, представленному в версии 2 AsyncHttpClient выпущенному на Abril 13th 2016, который уже имеет встроенную поддержку CompletableFuture<T> .

Исходный ответ с использованием версии 1 AsyncHttpClient:

Для этого у нас есть два возможных подхода:

  • первый использует неблокирующий IO, и я называю его AccessTheWebAsyncNio . Тем не менее, поскольку AsyncCompletionHandler является абстрактным классом (вместо функционального интерфейса), мы не можем передавать лямбда в качестве аргумента. Таким образом, это связано с неизбежной многословностью из-за синтаксиса анонимных классов. Однако это решение наиболее близко к потоку выполнения данного примера C # .

  • второй - немного менее подробный, однако он отправит новую задачу, которая в конечном итоге заблокирует поток на f.get() пока ответ не будет завершен.

Первый подход , более подробный, но не блокирующий:

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

Второй подход менее подробный, но блокирующий поток:

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

async и ожидают синтаксических сахаров. Суть асинхронного ожидания и ожидания - это конечный автомат. Компилятор преобразует ваш код async / await в конечный автомат.

В то же время для того, чтобы async / ожидал, что это действительно осуществимо в реальных проектах, нам нужно иметь множество функций библиотеки ввода-вывода Async уже на месте. Для C # большинство оригинальных функций синхронизированного ввода-вывода имеют альтернативную версию Async. Причина, по которой нам нужны эти функции Async, заключается в том, что в большинстве случаев ваш собственный код async / await сведен к некоторому методу Async библиотеки.

Функции библиотеки версий Async на C # похожи на концепцию AsynchronousChannel в Java. Например, у нас есть AsynchronousFileChannel.read, который может либо вернуть будущее, либо выполнить обратный вызов после выполнения операции чтения. Но это не совсем то же самое. Все функции C # Async возвращают задачи (похожие на Future, но более мощные, чем Future).

Итак, предположим, что 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);
}

Тогда я бы предположил, что компилятор преобразует исходный код async / wait в нечто вроде этого:

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

И вот реализация для 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);
    }
}




java