web-dev-qa-db-ja.com

プロジェクトリアクターまたはakkaストリームでは、シンクとサブスクライバーの概念的な違いは何ですか?

シンクとサブスクライバーの概念は私に似ています。また、リアクティブストリーム仕様で明示的に定義されているシンクの概念は見当たりません。

29
Jatin

Oleh Dokuka、 Project Reactor (そこに免責事項がありません)、 回答を投稿 から、しかし、その仮定の多くについて Akka Streams および Reactive Streams は間違っているので、以下で明確にすることができます。

免責事項:私は初期の頃からReactive Streamsに参加しました authored ほとんどの Technology Compatibility Kit 。また、AkkaおよびAkka Streamsを管理しています。

また、Reactive StreamsはJava 9に含まれており、 Java.util.concurrent.Flow。* として知られているため、RSに関する以下のコメントはすべて含まれています。 _j.u.c.Flow.Subscriber_とその他の型についてはまったく同じです。


答え

リアクティブストリームはサービスプロバイダーインターフェイス(SPI)仕様です

リアクティブストリーム、特にパブリッシャー/サブスクライバー/サブスクリプション/プロセッサータイプは、 サービスプロバイダーインターフェイス です。これは、2014年に遡る仕様に関する 初期の議論 でも確認されています。

仕様の初期の頃には、仕様のタイプでさえ、パブリッシャー、サブスクライバー、およびその他のタイプを隠そうとしました。残念なことに、APIは当時考慮されていたAPIに関係なく型がリークします したがって、API(!)は削除され、SPI型はすべて残っています です。

最近では、Reactive Streamsの実装によっては、これらのタイプを直接拡張することが何らかの理由でメリットがあると主張しています。これは正しくないため、そうではなく、Reactive Streamsインターフェースの目標でもありません。むしろ、これらのタイプが何であるかについての誤解です。厳密には、Reactive Streamsライブラリーが理解して「話す」ことに同意する相互運用インターフェース(プロトコル)です。

参考までに、RxJava 2.0とReactorはこれらのタイプを直接拡張しますが、Akka Streamsはアプリケーション開発者プログラミングインターフェースとしてRSを非表示にすることでRSの設計と原則に忠実です。これがSinkがSubscriberを拡張しない理由です。これは、人々がIS-Aの直接の関係を主張する「ネイティブサポート」とは関係ありません(むしろ、相互運用ライブラリが「ネイティブ」であると主張することは概念の誤解です)。

シンクとサブスクライバー、ソースとパブリッシャー

シンクとサブスクライバーの概念は私に似ています。

正しい、彼らは意図的に、そして設計上、似ています。

シンクは、サブスクライバを効果的に生成する何かの リフト表現 であるためです。簡略化するために、これを「サブスクライバーファクトリー」と考えることができます(具体的には、シンクは「青写真」であり、マテリアライザーはシンクの青写真を取得し、ソースのパブリッシャーとシンクのサブスクライバーを含む適切なRSステージを作成します。 Sink.ignoreと言うと、実際にはファクトリであり、Reactive Streamsによると、すべての要求と無視を実行するサブスクライバーを作成することになります。

同じことがSourceにも当てはまります。これは、リアクティブストリームPublisherと1:1で関連付けられています。したがって、Source.single(1)は、内部的にそれが仕事をするPublisherに具体化するものです。下流で許可されている場合、その1つの要素を放出します。

A.K.A.リアクティブストリームにシンクがないのはなぜですか?

前述のように、Akka's Sinkはサブスクライバーを直接拡張しません。ただし、基本的にはそれらの工場です。

「通常の使用中に、ユーザーはこれらの発行者/購読者タイプをまったく見ませんか?」と尋ねることができます。答えは「はい」です。これは機能であり、設計目標でもあります(Reactive Streamsに準拠)。基になるパブリッシャーとサブスクライバーのインスタンスが常にユーザーに直接公開されている場合、それらを誤って呼び出してバグや混乱を引き起こす可能性があります。これらのタイプが明示的に要求されない限り公開されない場合、偶発的なミスの可能性は低くなります!

その設計を誤解し、Akka Streamsには「ネイティブ」サポートがないと主張する人もいます(これは事実ではありません)。 APIでサブスクライバーからデタッチされることで得られるものを見てみましょう。

また、リアクティブストリーム仕様で明示的に定義されているシンクの概念は見当たりません。

確かに、シンクはリアクティブストリームの一部ではなく、それは絶対に問題ありません。

「Sink IS-A Subscriber」を回避することの利点

SinksはAkka Streamsの一部であり、その目的は、流れるようなDSLを提供することと、Subscribersの工場になることです。つまり、SubscriberがLEGOブロックである場合、Sinkはそれらを構築するものです(そして、Akka Stream Materializerはそれらを「実行」するためにさまざまなLEGOブロックをまとめるものです)。

実際、Sinkがサブスクライバーとの決定的なIS-Aを一切運ばないことはユーザーにとって有益です(sic!)

これは、_org.reactivestreams.Subscriber_がJava 9に含まれ、Java自体の一部になったため、ライブラリは_Java.util.concurrent.Flow.Subscriber_の代わりに_org.reactivestreams.Subscriber_。Reactive Streams型を公開して直接拡張することを選択したライブラリは、JDK9型を適応させるのに苦労します-サブスクライバと友人を拡張するすべてのクラスをコピーする必要がありますまたは、まったく同じインターフェースを拡張するために変更されましたが、異なるパッケージからAkkaでは、JDK9がリリースされた日から、すでにサポートされているJDK9型を要求するときに新しい型を公開します。

Reactive StreamsがSPI-サービスプロバイダーインターフェイス-これは、ライブラリが共有するためのものであり、「同じタイプとプロトコルを話す」ことができます。AkkaStreamsが行うすべての通信、および他のリアクティブストリームライブラリは、これらのルールを順守します。他のライブラリをAkka Streamsに接続する場合は、それを実行します。AkkaStreamsには、サブスクライバー、プロセッサー、またはパブリッシャー。シンクではなく、それがAkkaの「Akka固有」DSL(ドメイン固有言語)であり、その上に利便性やその他の機能を追加し、サブスクライバータイプを(意図的に!)隠します。

Akka(および正直に言うと、他のRS実装も同様にそうすることを推奨しましたが、そうしないことを選択しました)がこれらのタイプを隠しているもう1つの理由は、間違ったことをしやすいからです。 サブスクライバーを渡すと、だれでもそれを呼び出すことができます。さらに、 無意識のうちにルールを破り、Reactive Streams仕様が要求することを保証します タイプと対話する誰からでも。

間違いの発生を防ぐため、Akka Streamsのリアクティブストリームタイプは「非表示」であり、明示的に要求された場合にのみ公開されます。