222 votes

L'équivalent Java de C# async/await ?

Je suis un développeur C# normal mais il m'arrive de développer des applications en Java. Je me demande s'il existe un équivalent Java de C# async/await ? En termes simples, quel est l'équivalent Java de :

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

3voto

stevebot Points 3911

Il n'y a rien de natif à Java qui vous permette de faire cela, comme les mots-clés async/await, mais ce que vous pouvez faire si vous le voulez vraiment, c'est utiliser un fichier de type CountDownLatch . Vous pourrait puis imiter async/await en le faisant passer (du moins en Java7). Il s'agit d'une pratique courante dans les tests unitaires Android, où nous devons effectuer un appel asynchrone (généralement un runnable posté par un gestionnaire), puis attendre le résultat (compte à rebours).

Cependant, l'utilisation de cette méthode dans votre application plutôt que dans votre test est PAS ce que je recommande. Ce serait extrêmement mal fait car CountDownLatch dépend du fait que vous décomptiez effectivement le bon nombre de fois et aux bons endroits.

2voto

stofu Points 31

J'ai créé et publié une bibliothèque Java async/await. https://github.com/stofu1234/kamaitachi

Cette bibliothèque n'a pas besoin d'extension de compilateur, et réalise un traitement IO sans pile en 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);
            }
            );
    }

1voto

Java n'a malheureusement pas d'équivalent d'async/await. Ce qui s'en rapproche le plus, c'est probablement ListenableFuture de Guava et le chaînage des auditeurs, mais il serait toujours très difficile d'écrire pour les cas impliquant de multiples appels asynchrones, car le niveau d'imbrication augmenterait très rapidement.

Si vous êtes d'accord pour utiliser un langage différent au-dessus de JVM, il existe heureusement async/await en Scala, qui est un équivalent direct d'async/await en C# avec une syntaxe et une sémantique presque identiques : https://github.com/scala/async/

Notez que, bien que cette fonctionnalité ait nécessité un support de compilateur assez avancé en C#, en Scala elle a pu être ajoutée en tant que bibliothèque grâce à un système de macro très puissant en Scala et peut donc être ajoutée même à des versions plus anciennes de Scala comme 2.10. De plus, Scala est compatible avec les classes de Java, ce qui signifie que vous pouvez écrire le code asynchrone en Scala et l'appeler depuis Java.

Il existe également un autre projet similaire appelé Akka Dataflow. http://doc.akka.io/docs/akka/2.3-M1/scala/dataflow.html qui utilise une formulation différente mais est conceptuellement très similaire, cependant implémentée en utilisant des continuations délimitées, et non des macros (elle fonctionne donc avec des versions de Scala même plus anciennes comme 2.9).

1voto

Loganathan Points 303

AsynHelper La bibliothèque Java comprend un ensemble de classes/méthodes utilitaires pour de tels appels asynchrones (et l'attente).

Si l'on souhaite exécuter un ensemble d'appels de méthodes ou de blocs de code de manière asynchrone, le programme comprend une méthode d'aide utile. AsyncTask .submitTasks comme dans l'extrait ci-dessous.

AsyncTask.submitTasks(
    () -> getMethodParam1(arg1, arg2),
    () -> getMethodParam2(arg2, arg3)
    () -> getMethodParam3(arg3, arg4),
    () -> {
             //Some other code to run asynchronously
          }
    );

Si l'on souhaite attendre que l'exécution de tous les codes asynchrones soit terminée, la fonction AsyncTask.submitTasksAndWait (en anglais) peut être utilisé.

De même, si l'on souhaite obtenir une valeur de retour à partir de chaque appel de méthode asynchrone ou bloc de code, la fonction AsyncSupplier .submitSuppliers peut être utilisé pour que le résultat puisse être obtenu à partir du tableau des fournisseurs de résultats renvoyé par la méthode. Voici un exemple d'extrait :

Supplier<Object>[] resultSuppliers = 
   AsyncSupplier.submitSuppliers(
     () -> getMethodParam1(arg1, arg2),
     () -> getMethodParam2(arg3, arg4),
     () -> getMethodParam3(arg5, arg6)
   );

Object a = resultSuppliers[0].get();
Object b = resultSuppliers[1].get();
Object c = resultSuppliers[2].get();

myBigMethod(a,b,c);

Si le type de retour de chaque méthode est différent, utilisez le type d'extrait ci-dessous.

Supplier<String> aResultSupplier = AsyncSupplier.submitSupplier(() -> getMethodParam1(arg1, arg2));
Supplier<Integer> bResultSupplier = AsyncSupplier.submitSupplier(() -> getMethodParam2(arg3, arg4));
Supplier<Object> cResultSupplier = AsyncSupplier.submitSupplier(() -> getMethodParam3(arg5, arg6));

myBigMethod(aResultSupplier.get(), bResultSupplier.get(), cResultSupplier.get());

Le résultat des appels de méthodes/blocs de code asynchrones peut également être obtenu à un autre point du code dans le même thread ou dans un thread différent, comme dans l'extrait ci-dessous.

AsyncSupplier.submitSupplierForSingleAccess(() -> getMethodParam1(arg1, arg2), "a");
AsyncSupplier.submitSupplierForSingleAccess(() -> getMethodParam2(arg3, arg4), "b");
AsyncSupplier.submitSupplierForSingleAccess(() -> getMethodParam3(arg5, arg6), "c");

//Following can be in the same thread or a different thread
Optional<String> aResult = AsyncSupplier.waitAndGetFromSupplier(String.class, "a");
Optional<Integer> bResult = AsyncSupplier.waitAndGetFromSupplier(Integer.class, "b");
Optional<Object> cResult = AsyncSupplier.waitAndGetFromSupplier(Object.class, "c");

 myBigMethod(aResult.get(),bResult.get(),cResult.get());

1voto

vipcxj Points 416

J'ai développé une bibliothèque JAsync pour faire ça. Il vient d'être publié aujourd'hui. Il rend l'expérience de programmation asynchrone du développeur aussi proche que possible de la programmation synchrone habituelle, y compris le style de code et le débogage. Voici l'exemple.

@RestController
@RequestMapping("/employees")
public class MyRestController {
    @Inject
    private EmployeeRepository employeeRepository;
    @Inject
    private SalaryRepository salaryRepository;

    // The standard JAsync async method must be annotated with the Async annotation, and return a Promise object.
    @Async()
    private Promise<Double> _getEmployeeTotalSalaryByDepartment(String department) {
        double money = 0.0;
        // A Mono object can be transformed to the Promise object. So we get a Mono object first.
        Mono<List<Employee>> empsMono = employeeRepository.findEmployeeByDepartment(department);
        // Transformed the Mono object to the Promise object.
        Promise<List<Employee>> empsPromise = JAsync.from(empsMono);
        // Use await just like es and c# to get the value of the Promise without blocking the current thread.
        for (Employee employee : empsPromise.await()) {
            // The method findSalaryByEmployee also return a Mono object. We transform it to the Promise just like above. And then await to get the result.
            Salary salary = JAsync.from(salaryRepository.findSalaryByEmployee(employee.id)).await();
            money += salary.total;
        }
        // The async method must return a Promise object, so we use just method to wrap the result to a Promise.
        return JAsync.just(money);
    }

    // This is a normal webflux method.
    @GetMapping("/{department}/salary")
    public Mono<Double> getEmployeeTotalSalaryByDepartment(@PathVariable String department) { 
        // Use unwrap method to transform the Promise object back to the Mono object.
        return _getEmployeeTotalSalaryByDepartment(department).unwrap(Mono.class);
    }
}

Et en mode débogage, vous pouvez voir toutes les variables, tout comme le code synchrone.

enter image description here

L'autre point fort de ce projet est qu'il est l'un des rares projets de ce type encore actifs à l'heure actuelle. Il vient juste d'être publié, il a donc beaucoup de potentiel.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X