47

Rx over TPL の使用を選択するのはいつですか? または 2 つのフレームワークは直交していますか?

私が理解していることから、Rxは主にイベントの抽象化を提供し、構成を可能にすることを目的としていますが、非同期操作の抽象化も可能にします。Createxx オーバーロードと Fromxxx オーバーロードを使用し、返された IDisposable を破棄してキャンセルします。

TPL は、タスクおよびキャンセル機能を介して操作の抽象化も提供します。

私のジレンマは、いつ、どのようなシナリオで、どれを使用するかということです。

4

5 に答える 5

50

Rx の主な目的は、イベントを抽象化することではありません。これは、その結果の 1 つにすぎません。その主な目的は、コレクションに構成可能なプッシュ モデルを提供することです。

IObservable<T>リアクティブ フレームワーク (Rx) は、 の数学的双対に基づいていIEnumerable<T>ます。したがって、 を使用してコレクションから項目を「プル」するのではなく、IEnumerable<T>を介してオブジェクトを「プッシュ」することができますIObservable<T>

もちろん、実際に観測可能なソースを探しに行くときは、イベントや非同期操作などは優れた候補です。

リアクティブ フレームワークには、観察可能なデータのソースを監視し、クエリとサブスクリプションを管理できるマルチスレッド モデルが当然必要です。Rx は実際にこれを行うために TPL を多用します。

したがって、Rx を使用すると、暗黙的に TPL を使用することになります。

タスクを直接制御したい場合は、TPL を直接使用します。

しかし、観察してクエリを実行したいデータ ソースがある場合は、リアクティブ フレームワークを徹底的にお勧めします。

于 2010-03-30T06:13:16.607 に答える
27

私が従うのが好きないくつかのガイドライン:

  • 私が作成したものではないデータを扱っていますか? いつ届くデータ?次にRX。
  • 私は計算を開始しており、並行性を管理する必要がありますか? 次にTPL。
  • 複数の結果を管理していて、時間に基づいて選択する必要がありますか? 次にRX。
于 2010-04-21T23:45:40.007 に答える
15

更新、2016 年 12 月: 30 分あれば、私の推測ではなく、Joe Duffy の直接の説明を読むことをお勧めします。私の分析はうまくいくと思いますが、この質問を見つけた場合は、TPL と Rx.NET に加えて、MS 研究プロジェクト (Midori、Cosmos) もカバーしているため、これらの回答の代わりにブログ投稿を参照することを強くお勧めします。

http://joeduffyblog.com/2016/11/30/15-years-of-concurrency/


.NET 2.0 が登場した後、MS は過剰修正という大きな間違いを犯したと思います。彼らは、会社のさまざまな部分から同時に多くの異なる同時実行管理 API を導入しました。

  • Steven Toub はスレッドセーフなプリミティブを Event ( として始まり、Future<T>に変わったTask<T>)に置き換えることを強く求めていました。
  • MS Research には MIN-LINQ と Reactive Extensions (Rx) がありました
  • ハードウェア/組み込みにはロボティクス カンタイム (CCR)がありました

その間、多くのマネージ API チームは APM と を共存させようとしていましたが、Toub が/を mscorlib.dll でThreadpool.QueueUserWorkItem()出荷するための戦いに勝つかどうかはわかりませんでした。最終的に、彼らはヘッジし、 mscorlib で と の両方を出荷したように見えますが、mscorlib で他の Rx API (でさえも) を許可しませんでした。この垣根が、結果的に膨大な量の重複を引き起こし (詳細は後述)、社内外で労力を浪費したと思います。Future<T>Task<T>Task<T>IObservable<T>ISubject<T>

重複については、 Taskvs. IObservable<Unit>Task<T>vs. AsyncSubject<T>Task.Run()vs.を参照してくださいObservable.Start()。そして、これは氷山の一角にすぎません。しかし、より高いレベルでは次のことを考慮してください。

  • StreamInsight - SQL イベント ストリーム、ネイティブ コードに最適化されていますが、LINQ 構文を使用して定義されたイベント クエリ
  • TPL Dataflow - TPL 上に構築され、Rx と並行して構築され、スレッド化の並列処理を微調整するために最適化されていますが、クエリの作成は得意ではありません
  • Rx - 驚くべき表現力ですが、危険をはらんでいます。'ホット' ストリームをIEnumerableスタイルの拡張メソッドと混合します。これは、非常に簡単に永久にブロックすることを意味します (First()ホット ストリームの呼び出しは返されません)。制限のスケジューリング (並列処理の制限) は、かなり奇妙なSubscribeOn()拡張メソッドを介して行われます。Rx の学習を開始する場合は、避けるべきすべての落とし穴を学習するために長い時間を確保してください。しかし、複雑なイベント ストリームを構成する場合や、複雑なフィルタリング/クエリが必要な場合は、実際には Rx が唯一のオプションです。

ISubject<T>MSが mscorlib で出荷されるまで、Rx が広く採用される可能性はないと思います。TimeInterval<T>Rx にはやなどの非常に便利な具象 (ジェネリック) 型がいくつか含まれているため、これは悲しいことTimestamped<T>ですNullable<T>。また、System.Reactive.EventPattern<TEventArgs>.

于 2013-01-21T19:15:37.240 に答える
13

Scott W の箇条書きが好きです。より具体的な例をRxマップにうまく配置するには

  • ストリームの消費
  • Web リクエストのようなノンブロッキング非同期作業を実行します。
  • ストリーミング イベント (マウスの動きなどの .net イベントまたは Service Bus メッセージ タイプのイベント)
  • イベントの「ストリーム」を一緒に構成する
  • Linq スタイルの操作
  • 公開 API からのデータ ストリームの公開

TPLはうまくマッピングされているようです

  • 仕事の内部並列化
  • Web リクエストなどの非ブロッキング非同期作業の実行
  • ワークフローと継続の実行

IObservable (Rx) で気づいたことの 1 つは、それが普及することです。コードベースに入ると、間違いなく他のインターフェイスを介して公開されるため、最終的にはアプリケーション全体に表示されます. これは最初は怖いかもしれないと思いますが、チームのほとんどは今では Rx にかなり慣れており、Rx によって節約できる作業量を気に入っています。

IMHO Rx は、.NET 3.5、4.0、Silverlight 3、Silverlight 4、および Javascript で既にサポートされているため、TPL よりも支配的なライブラリになります。これは、効果的に 1 つのスタイルを習得する必要があり、多くのプラットフォームに適用できることを意味します。

編集: Rx が TPL よりも優勢であることについて考えを変えました。それらは異なる問題を解決するので、実際にはそのように比較すべきではありません。.NET 4.5/C# 5.0 では、async/await キーワードによってさらに TPL に結び付けられます (これは良いことです)。Rx vs イベント vs TPL などについての深い議論については、私のオンライン本IntroToRx.comの最初の章をチェックしてください。

于 2010-07-16T08:17:12.083 に答える
10

TPL Dataflow は、Rx の機能の特殊なサブセットをカバーしていると言えます。データフローは、かなりの時間がかかる可能性のあるデータ処理用です。一方、Rx は、処理時間が無視できるマウス位置、エラー状態などのイベント用です。

例: 「subscribe」ハンドラーが非同期で、一度に 1 つ以上のエグゼキューターを必要としない場合。Rx ではブロックする必要があります。Rx は非同期にとらわれず、多くの場所で特別な方法で非同期を脅かさないため、それを回避する方法は他にありません。

.Subscribe(myAsyncHandler().Result)

ブロックしない場合、Rx はハンドラーがまだ非同期で実行されている間にアクションが完了したと見なします。

やったらこう思うかもしれません。

.ObserveOn(Scheduler.EventLoopSchedule)

問題は解決しました。ただし、これにより .Complete() ワークフローが中断されます。Rx は、実行をスケジュールするとすぐに完了したと見なし、非同期操作の完了を待たずにアプリケーションを終了するためです。

Rx よりも 4 つ以下の同時非同期タスクを許可する場合、すぐに使用できるものは何もありません。独自のスケジューラーやバッファーなどを実装することで、何かをハックできるかもしれません。

TPL Dataflow は、ActionBlock で非常に優れたソリューションを提供します。同時アクションを特定の数に絞り込むことができ、非同期操作を理解するので、Complete() を呼び出して Completed を待つことは、まさに期待どおりのことを行います: 進行中のすべての非同期タスクが完了するのを待ちます。

TPL が持つもう 1 つの機能は、「背圧」です。処理ルーチンでエラーを発見し、先月のデータを再計算する必要があるとします。Rx を使用してソースをサブスクライブし、パイプラインに無制限のバッファーまたは ObserveOn が含まれている場合、ソースは処理が処理できるよりも速く読み取り続けるため、数秒でメモリが不足します。ブロッキング コンシューマーを実装したとしても、ソースが非同期の場合など、ソースがブロッキング呼び出しに悩まされる可能性があります。TPLでは、ソースを次のように実装できます

while(...)
    await actionBlock.SendAsync(msg)

ハンドラーがオーバーロードされている間、ソースをまだブロックしません。

全体として、Rx は時間と計算量が少ないアクションに適していることがわかりました。処理時間がかなりの量になると、奇妙な副作用と難解なデバッグの世界にいることになります。

良いニュースは、TPL Dataflow ブロックが Rx で非常にうまく機能することです。これらには AsObserver/AsObservable アダプターがあり、必要に応じて Rx パイプラインの途中に配置できます。しかし、Rx にはもっと多くのパターンとユースケースがあります。したがって、私の経験則では、Rx から始めて、必要に応じて TPL データフローを追加します。

于 2015-04-13T20:12:57.373 に答える