web-dev-qa-db-fra.com

map vs flatMap dans le réacteur

J'ai trouvé beaucoup de réponses concernant RxJava , mais je veux comprendre comment cela fonctionne dans Reactor.

Ma compréhension actuelle est très vague, j'ai tendance à penser que la carte est synchrone et flatMap à être asynchrone, mais je ne peux pas vraiment m'en sortir.

Voici un exemple:

files.flatMap { it ->
    Mono.just(Paths.get(UPLOAD_ROOT, it.filename()).toFile())
        .map {destFile ->
            destFile.createNewFile()
            destFile    
        }               
        .flatMap(it::transferTo)
}.then()  

J'ai des fichiers (un Flux<FilePart>) et je veux le copier sur certains UPLOAD_ROOT sur le serveur.

Cet exemple est tiré d'un livre.

Je peux changer tous les .map à .flatMap et vice versa et tout fonctionne toujours. Je me demande quelle est la différence.

18
shredding
  • map est destiné aux transformations synchrones, non bloquantes, de 1 à 1
  • flatMap est destiné aux transformations asynchrones (non bloquantes) de 1 à N

La différence est visible dans la signature de la méthode:

  • map prend un Function<T, U> et renvoie un Flux<U>
  • flatMap prend un Function<T, Publisher<V>> et renvoie un Flux<V>

C'est le principal indice: vous pouvez passer un Function<T, Publisher<V>> à un map, mais il ne saurait pas quoi faire avec le Publishers, et cela se traduirait par un Flux<Publisher<V>>, une séquence d'éditeurs inertes.

D'un autre côté, flatMap attend un Publisher<V> pour chaque T. Il sait quoi en faire: abonnez-vous et propagez ses éléments dans la séquence de sortie. Par conséquent, le type de retour est Flux<V>: flatMap aplatira chaque intérieur Publisher<V> dans la séquence de sortie de tous les Vs.

À propos de l'aspect 1-N:

pour chaque <T> élément d'entrée, flatMap le mappe à un Publisher<V>. Dans certains cas (par exemple, une requête HTTP), cet éditeur n'émettra qu'un seul élément, auquel cas nous sommes assez proches d'un async map.

Mais c'est le cas dégénéré. Le cas générique est qu'un Publisher peut émettre plusieurs éléments, et flatMap fonctionne tout aussi bien.

Par exemple, imaginez que vous disposez d'une base de données réactive et que vous flatMap à partir d'une séquence d'ID utilisateur, avec une demande qui renvoie l'ensemble d'un utilisateur de Badge. Vous vous retrouvez avec un seul Flux<Badge> de tous les badges de tous ces utilisateurs.

map est-il vraiment synchrone et non bloquant ?

Oui: il est synchrone dans la façon dont l'opérateur l'applique (un simple appel de méthode, puis l'opérateur émet le résultat) et non bloquant dans le sens où la fonction elle-même ne doit pas bloquer l'opérateur qui l'appelle. En d'autres termes, cela ne devrait pas introduire de latence. En effet, un Flux est toujours asynchrone dans son ensemble. S'il bloque la mi-séquence, il affectera le reste du traitement Flux, ou même d'autres Flux.

Si votre fonction de carte bloque/introduit une latence mais ne peut pas être convertie pour renvoyer un Publisher, envisagez publishOn/subscribeOn pour compenser ce travail de blocage sur un thread séparé.

31
Simon Baslé