82 votes

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, la sortie sera de 2. Maintenant, dans le cas d' 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 sont à exécuter dans un thread séparé et "en même temps" (c'est à dire suivant thenApplyAsyncs commencé avant thenApplyAsyncs finition), si oui, quel est l'argument d'entrée de la valeur de la deuxième étape, si la première étape n'est pas fini?

Où en sera le résultat de la première étape aller si pas pris par la deuxième étape? la troisième étape sera de prendre une étape du résultat?

Si la deuxième étape a attendre le résultat de la première étape, alors quel est le point 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 temps de calcul.

74voto

Kiskae Points 11240

La différence a à voir avec l' Executor qui est 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 fil définie par l' CompleteableFuture sur laquelle il est appelé, de sorte que vous ne sont généralement pas savoir d'où cela sera exécutée. Il peut exécuter immédiatement si le résultat est déjà disponible.
  2. thenApplyAsync(fn) - exécute fn sur un environnement défini par l'exécuteur 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 le même, mais la programmation, le comportement dépend du choix de la méthode.

42voto

1283822 Points 759

Je dois faire remarquer que les noms de thenApply et thenApplyAsync est absolument horrible et déroutant. Il n'y a rien en thenApplyAsync qui est plus asynchrone qu' thenApply le contrat de ces méthodes.

La différence est à faire avec sur le thread de la fonction est exécutée. La fonction fournis thenApply peut s'exécuter sur l'un des threads qui

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

alors qu' thenApplyAsync soit utilise une valeur par défaut Executor (aka. pool de threads), ou fourni de l' Executor.

La partie asynchrone de ces fonctions a à voir avec le fait qu'une opération asynchrone finalement appels complete ou completeExceptionally. L'idée est venue de Javascript qui n'a rien à voir avec le multithreading.

1voto

Willi Mentzel Points 7681

C'est ce que dit la documentation à propos de CompletableFuture's thenApplyAsync:

Retourne une nouvelle CompletionStage que, lorsque cette étape est terminée normalement, c'est exécutée à l'aide de cette étape est asynchrone par défaut exécution de l'installation, à ce stade du résultat que l'argument de la fonction fournie.

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

Dans votre cas, vous faites d'abord le travail synchrone et puis asynchrone un. Donc, il n'est pas question que le second est asynchrone, car il est démarré qu'après la synchrounous travail est terminé.

Nous allons passer. Dans certains cas, "async résultat: 2" sera imprimée pour la première fois et, dans certains cas, "résultat de la synchronisation: 2" sera imprimée pour la première fois. Ici, il fait une différence parce que les deux composez le 1 et 2 peuvent s'exécuter de manière asynchrone, composez le 1 sur un thread séparé et appels 2 sur un autre thread, ce 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));

1voto

user1235217 Points 23

La deuxième étape (c'est à dire le calcul) sera toujours exécuté après la première étape.

Si la deuxième étape a attendre le résultat de la première étape, alors quel est le point de Async?

Asynchrone signifie dans ce cas que vous avez la garantie que la méthode sera de retour rapidement et le calcul sera exécutée dans un thread différent.

Lors de l'appel d' thenApply (sans async), alors vous n'avez aucune garantie. Dans ce cas, le calcul peut être exécutée de manière synchrone c'est à dire dans le même thread qui appelle thenApply si le CompletableFuture est déjà terminée au moment où la méthode est appelée. Mais le calcul peut également être exécutée de manière asynchrone par le thread qui complète le futur ou à un autre thread qui appelle une méthode sur le même CompletableFuture. Cette réponse: https://stackoverflow.com/a/46062939/1235217 expliqué en détail ce thenApply ne et ne garantie pas.

Donc, quand devez-vous utiliser thenApply et quand thenApplyAsync? J'utilise la règle suivante:

  • non-async: uniquement si la tâche est très petite et non-bloquant, car dans ce cas nous ne se soucient pas les threads de l'exécute
  • async (souvent explicite exécuteur comme paramètre): pour toutes les autres tâches

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