web-dev-qa-db-fra.com

Quelle est la différence entre thenApply et thenApplyAsync de Java CompletableFuture?

Supposons que j'ai le code suivant:

CompletableFuture<Integer> future  
        = CompletableFuture.supplyAsync( () -> 0);

thenApply cas:

future.thenApply( x -> x + 1 )
      .thenApply( x -> x + 1 )
      .thenAccept( x -> System.out.println(x));

Ici, le résultat sera 2. Maintenant, dans le cas de thenApplyAsync:

future.thenApplyAsync( x -> x + 1 )   // first step
      .thenApplyAsync( x -> x + 1 )   // second step
      .thenAccept( x -> System.out.println(x)); // third step

J'ai lu dans ce blog que chaque thenApplyAsync est exécutée dans un thread séparé et 'en même temps' (c'est-à-dire après thenApplyAsyncs commencé avant précédent thenApplyAsyncs finish), si c'est le cas, quelle est la valeur d'argument d'entrée de la deuxième étape si la première étape n'est pas terminée?

Où ira le résultat de la première étape s'il n'est pas pris par la deuxième étape? la troisième étape va prendre le résultat de quelle étape?

Si la deuxième étape doit attendre le résultat de la première étape, alors quel est l'intérêt de Async?

Ici x -> x + 1 est juste pour montrer le point, ce que je veux savoir, c’est dans les cas de très long calcul.

15
Yulin

La différence concerne la Executor responsable de l'exécution du code. Chaque opérateur sur CompletableFuture a généralement 3 versions.

  1. thenApply(fn) - exécute fn sur un thread défini par la CompleteableFuture sur laquelle elle est appelée, de sorte que vous ne pouvez généralement pas savoir où elle sera exécutée. Il peut s'exécuter immédiatement si le résultat est déjà disponible.
  2. thenApplyAsync(fn) - exécute fn sur un exécuteur défini par l'environnement, quelles que soient les circonstances. Pour CompletableFuture, ce sera généralement ForkJoinPool.commonPool().
  3. thenApplyAsync(fn,exec) - exécute fn sur exec.

En fin de compte, le résultat est identique, mais le comportement de planification dépend du choix de la méthode.

14
Kiskae

Je dois souligner que les noms thenApply et thenApplyAsync sont absolument horribles et déroutants. Il n'y a rien dans thenApplyAsync qui soit plus asynchrone que thenApply du contrat de ces méthodes. 

La différence concerne le thread sur lequel la fonction est exécutée. La fonction fournie à thenApplypeut s’exécuter sur l’un des threads that

  1. appelez complete
  2. appeler thenApply sur la même instance

alors que thenApplyAsync utilise soit une Executor par défaut (pool de threads), soit une Executor fournie.

La partie asynchrone de ces fonctions concerne le fait qu’une opération asynchrone appelle finalement complete ou completeExceptionally. L'idée vient de Javascript, qui n'a rien à voir avec le multithreading.

1
1283822

C’est ce que dit la documentation sur CompletableFuture'sthenApplyAsync :

Retourne un nouveau CompletionStage qui, à la fin de cette étape normalement, est exécuté en utilisant la valeur asynchrone par défaut de cette étape fonction d'exécution, avec le résultat de cette étape comme argument de la fonction fournie.

Donc, thenApplyAsync doit attendre le résultat précédent thenApplyAsync's:

Dans votre cas, vous effectuez d’abord le travail synchrone, puis asynchrone. Ainsi, peu importe que le second soit asynchrone car il est démarré uniquement une fois le travail synchrone terminé.

Allumons-le. Dans certains cas, "résultat asynchrone: 2" sera imprimé en premier et dans certains cas, "résultat de synchronisation: 2" sera imprimé en premier. Cela fait une différence, car les appels 1 et 2 peuvent être exécutés de manière asynchrone, appeler 1 sur un thread séparé et 2 sur un autre thread, qui peut être le thread principal.

CompletableFuture<Integer> future
                = CompletableFuture.supplyAsync(() -> 0);

future.thenApplyAsync(x -> x + 1) // call 1
                .thenApplyAsync(x -> x + 1)
                .thenAccept(x -> System.out.println("async result: " + x));

future.thenApply(x -> x + 1) // call 2
                .thenApply(x -> x + 1)
                .thenAccept(x -> System.out.println("sync result:" + x));
0
Willi Mentzel