web-dev-qa-db-ja.com

リアクタ内のマップとフラットマップ

RxJava に関する多くの答えを見つけましたが、Reactorでの動作を理解したいと思います。

私の現在の理解は非常に曖昧です。地図は同期的であり、flatMapは非同期であると考える傾向がありますが、実際に理解することはできません。

以下に例を示します。

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

ファイル(Flux<FilePart>)があり、サーバー上のいくつかのUPLOAD_ROOTにコピーしたい。

この例は本から取られています。

すべての.map.flatMapに、またはその逆に変更できますが、すべてが引き続き機能します。違いは何でしょうか。

18
shredding
  • mapは、同期、非ブロッキング、1対1変換用です
  • flatMapは、非同期(非ブロッキング)1-N変換用です

違いはメソッドシグネチャで確認できます。

  • mapFunction<T, U>を取り、Flux<U>を返します
  • flatMapFunction<T, Publisher<V>>を取り、Flux<V>を返します

それが主要なヒントです。あなたはcanFunction<T, Publisher<V>>mapに渡しますが、Publishersをどうするかわかりません。 Flux<Publisher<V>>で、不活性なパブリッシャーのシーケンス。

一方、flatMapでは、TごとにPublisher<V>が必要です。それをどうするかを知っています。サブスクライブし、その要素を出力シーケンスに伝播します。その結果、戻り値の型はFlux<V>です。flatMapは、各内部Publisher<V>all the Vsの出力シーケンスにフラット化します。

1-Nアスペクトについて:

<T>入力要素ごとに、flatMapはそれをPublisher<V>にマップします。場合によっては(たとえば、HTTP要求)、そのパブリッシャーは1つのアイテムのみを発行します。その場合、非同期mapにかなり近づいています。

しかし、それは退化したケースです。一般的なケースは、Publisherが複数の要素を放出でき、flatMapも同様に機能するということです。

例として、リアクティブデータベースがあり、ユーザーの一連のBadgeを返すリクエストを使用して、ユーザーIDのシーケンスからflatMapを想像してください。これらすべてのユーザーのすべてのバッジのうち、単一のFlux<Badge>になります。

mapは本当に同期であり、ノンブロッキング

はい:オペレーターが適用する方法で同期し(単純なメソッド呼び出し、そしてオペレーターが結果を出力する)、関数自体がそれを呼び出すオペレーターをブロックしてはならないという意味で非ブロッキングです。言い換えれば、レイテンシを導入するべきではありません。 Fluxは全体としてまだ非同期であるためです。シーケンスの途中でブロックすると、残りのFlux処理、または他のFluxにも影響します。

マップ関数がブロッキング/レイテンシーを導入しているが、Publisherを返すように変換できない場合は、publishOn/subscribeOnを考慮して、別のスレッドでのブロッキング作業を相殺してください。

31
Simon Baslé