Frage

Wann möchten Sie auf einen Blick Rx über TPL verwenden, oder sind die 2-Frameworks orthogonal?

Von dem, was ich verstehe, Rx in erster Linie eine Abstraktion über Ereignisse gedacht zu schaffen und die Zusammensetzung erlauben, aber es erlaubt auch eine Abstraktion über Asynchron-Operationen bereitzustellen. mit der Createxx Überlastungen und die von XXX Überlastungen und Löschung der IDisposable zurück über entsorgen.

TPL stellt auch eine Abstraktion für den Betrieb über den Task und Löschung Fähigkeiten.

Mein Dilemma ist, wenn die verwenden und für das, was Szenarien?

War es hilfreich?

Lösung

Der Hauptzweck der Rx ist nicht eine Abstraktion über Ereignisse zu liefern. Dies ist nur eines seiner Ergebnisse. Sein Hauptzweck ist es, ein zusammensetzbaren Push-Modell für Sammlungen zur Verfügung zu stellen.

Der reaktive Rahmen (Rx) auf IObservable<T> Basis die mathematischen dualen IEnumerable<T> zu sein. Also statt „pull“ Elemente aus einer Sammlung IEnumerable<T> mit uns Objekte „geschoben“ wir über IObservable<T> haben.

Natürlich, wenn wir gehen eigentlich für beobachtbare Quellen suchen Dinge wie Events und Asynchron-Operationen sind ausgezeichnete Kandidaten.

Der reaktive Rahmen erfordert natürlich ein Multi-Threaded-Modell in der Lage sein, die Quellen der beobachtbaren Daten zu beobachten und Abfragen und Abonnements zu verwalten. Rx tatsächlich macht intensiven Gebrauch von der TPL, dies zu tun.

Wenn Sie also Rx verwenden Sie die TPL implizit verwendet wird.

Sie würden die TPL direkt verwenden, wenn Sie die direkte Kontrolle über Ihre Aufgaben wünschen.

Aber wenn Sie Datenquellen haben, die Sie wünschen Anfragen zu beobachten und führen gegen dann gründlich ich den reaktiven Rahmen empfehlen.

Andere Tipps

Einige Richtlinien, die ich folgen mögen:

  • Bin ich mit den Daten zu tun, dass ich ihren Ursprung nicht. Daten, die ankommt, wenn es gefällt? Dann RX.
  • Bin ich mit Ursprung Berechnungen und Notwendigkeit Gleichzeitigkeit zu verwalten? Dann TPL.
  • Verwaltung Bin ich mehrere Ergebnisse und Notwendigkeit von ihnen basierend auf Zeit zu wählen? Dann RX.

ich wie Scott Ws Aufzählungszeichen. Setzen einige weitere konkrete Beispiele in Rx Karten wirklich schön zu

  • raubend Ströme
  • Ausführen nicht blockierende Asynchron Arbeit wie Web-Anfragen.
  • Veranstaltungen Streaming (entweder .net Ereignisse wie Mausbewegung oder Servicebus Nachrichtentyp Ereignisse)
  • Composing "Streams" von Ereignissen zusammen
  • Linq Stil Operationen
  • Offenlegen von Datenströmen aus dem öffentlichen API

TPL scheint gut zur Karte

  • interne Parallelisierung der Arbeit
  • Ausführen nicht blockierende Asynchron Arbeit wie Webanfragen
  • Ausführen Arbeitsabläufe und Fortsetzungen

Eine Sache, die ich mit IObservable (Rx) bemerkt habe, ist, dass es allgegenwärtig wird. Nachdem Sie in der Code-Basis, da es keinen Zweifel über andere Schnittstellen ausgesetzt wird, wird es schließlich überall auf Ihrer Anwendung erscheinen. Ich stelle mir dies zunächst beängstigend sein kann, aber die meisten des Teams ist ziemlich komfortabel mit Rx jetzt und lieben die Menge der Arbeit, die es uns erspart.

IMHO Rx wird die dominante Bibliothek über die TPL sein, wie es bereits in .NET 3.5 unterstützt wird, 4.0, Silverlight 3, Silverlight 4 und Javascript. Das heißt, Sie müssen effektiv einen Stil lernen und es ist auf vielen Plattformen.

Bearbeiten : Ich habe meine Meinung über Rx dominant über TPL verändert. Sie lösen verschiedene Probleme so nicht wirklich so verglichen werden. Mit .NET 4.5 / C # 5.0 die Asynchron / await keywords weiter binden uns an die TPL (was gut ist). Für eine weitere discuson auf Rx vs Ereignisse vs TPL usw. überprüfen Sie die erste Kapitel mein Online-Buch IntroToRx.com

Update Dezember 2016: Wenn Sie 30 Minuten haben, empfehle ich Ihnen Joe Duffy lesen erster Hand statt meiner Spekulation. Ich glaube, meine Analyse hält gut, aber wenn Sie diese Frage gefunden habe ich dich sehe, anstatt diese Antworten den Blog-Eintrag sehr empfehlen, da neben TPL vs Rx.NET er auch MS Forschungsprojekte (Midori, Cosmos) abdeckt.

http://joeduffyblog.com/2016/ 30.11 / 15 Jahre-of-Concurrency /


Ich denke, MS einen großen Fehler Überkorrektur gemacht, nachdem .NET 2.0 herauskam. Sie führten viele verschiedene Concurrency Management APIs alle zur gleichen Zeit aus verschiedenen Teilen des Unternehmens.

  • Steven Toub war hart für Thread-sichere Primitiven schieben Ereignis zu ersetzen (die als Future<T> und verwandelte sich in Task<T> gestartet)
  • MS-Forschung hatte MIN-LINQ und Reactive Extensions (Rx)
  • Hardware / Embedded had Robotik cuntime (CCR)

In der Zwischenzeit viele verwaltete API-Teams versuchten, mit APM und Threadpool.QueueUserWorkItem() zu leben, nicht zu wissen, ob Toub seinen Kampf gewinnen würde Future<T> / Task<T> in mscorlib.dll zu versenden. Am Ende sieht es aus wie sie abgesichert und versandt sowohl Task<T> und IObservable<T> in mscorlib, aber war es nicht möglich andere Rx APIs (nicht einmal ISubject<T>) in mscorlib. Ich denke, diese Hecke eine riesige Menge an Duplizierung verursacht endete (dazu später mehr) und vergebliche Mühe innerhalb und außerhalb des Unternehmens.

Für Vervielfältigung siehe: Task vs. IObservable<Unit>, Task<T> vs. AsyncSubject<T>, Task.Run() vs. Observable.Start(). Und das ist nur die Spitze des Eisbergs. Aber auf einer höheren Ebene betrachten:

  • Stream - SQL-Ereignisströme, Native-Code-Optimierung, aber Ereignisabfragen definiert mithilfe von LINQ-Syntax
  • TPL Datenfluss - auf TPL gebaut, parallel zu Rx gebaut, für Zwicken Threading Parallelität optimiert, nicht gut im Komponieren Abfragen
  • Rx - erstaunliche Ausdruckskraft, aber voller Gefahren. Mixes ‚hot‘ Ströme mit IEnumerable-Stil Erweiterungsmethoden, die Sie ganz einfach bedeuten, für immer blockieren (First() an einem heißen Strom nie kehrt Aufruf). Scheduling Grenzen (Grenz Parallelität) über ziemlich seltsam SubscribeOn() Erweiterungsmethoden durchgeführt, die weirdly implizite und schwer richtig zu machen. Wenn das Starten Rx Reserve eine lange Zeit zu lernen, alle Fallen zu vermeiden lernen. Aber Rx ist wirklich die einzige Option, wenn komplexe Ereignisströme zu komponieren oder Sie benötigen komplexe Filterung / Abfrage-.

Ich glaube nicht, Rx eine reelle Chance auf breite Akzeptanz hat, bis MS Schiffe in mscorlib ISubject<T>. Welches ist traurig, weil Rx einige sehr nützliche Beton (Generika) Arten, wie TimeInterval<T> und Timestamped<T> enthält, die ich denke, in Kern / mscorlib wie Nullable<T> sein sollte. Auch System.Reactive.EventPattern<TEventArgs>.

Ich würde sagen, dass TPL Datenfluß-Abdeckungen spezialisiert Teilmengen der Funktionalität in Rx. Datenfluss ist, für die Datenverarbeitung, die messbare Menge an Zeit in Anspruch nehmen kann, während die Rx für Ereignisse, wie beispielsweise Mausposition, Fehlerzuständen, usw., wo die Zeit der Handhabung vernachlässigbar ist.

Beispiel: Ihr „subscribe“ Handler ist asynchron und Sie wollen nicht mehr als 1 Testamentsvollstrecker zu der Zeit. Mit Rx haben Sie Block, gibt es keinen anderen Weg darum herum, weil Rx Asynchron-agnostisch ist und nicht Gefahr async in besonderer Weise an vielen Orten.

.Subscribe(myAsyncHandler().Result)

Wenn Sie nicht blockieren, dann wird Rx der Ansicht, dass Aktion abgeschlossen ist, während Handler noch asynchron ausgeführt werden wird.

Sie können das denken, wenn Sie tun

.ObserveOn(Scheduler.EventLoopSchedule)

als Problem gelöst. Aber dies wird Ihre Das Gesamt () Workflow brechen, weil Rx denken, dass es so bald geschehen wird, wie es die Ausführung planen und Sie werden Ihre Anwendung beenden, ohne Asynchron-Betrieb Fertigstellung zu warten.

Wenn Sie nicht mehr als 4 Aufgaben gleichzeitig Asynchron ermöglichen als Rx nichts bietet aus der Box. Vielleicht können Sie etwas hacken von Ihrem eigenen Scheduler Implementierung, Puffer, etc.

TPL Datenfluss bietet sehr schöne Lösung in ActionBlock. Es kann gleichzeitige Aktionen zu bestimmten Anzahl drosseln und Asynchron-Operationen, so ruft Complete () und wartet verstehen genau tun wird abgeschlossen, was man erwarten würde. Warten auf all in-progress Asynchron-Aufgaben zu erledigen

Ein weiteres Merkmal TPL hat, ist „Gegendruck“. Angenommen, Sie haben einen Fehler in der Behandlungsroutine und Notwendigkeit entdeckten im letzten Monat Daten recalc. Wenn Sie Ihre Quelle abonnieren Rx verwenden und die Pipeline enthält unbegrenzte Puffer oder ObserveOn, als Sie in wenigen Sekunden genügend Speicherplatz aus, weil Quelle schneller halten das Lesen als Verarbeitung handhaben kann. Auch wenn Sie Verbraucher implementieren zu blockieren, kann Ihre Quelle blockiert Anrufe, zum Beispiel leiden, wenn Quelle asynchron ist. In TPL können Sie implementieren Quelle als

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

, die nicht Quelle blockiert noch wird warten, während Handler überlastet ist.

Insgesamt fand ich, dass Rx ist gut für Aktionen, die Zeit und rechen Licht. Wenn die Verarbeitungszeit wesentlich wird, sind Sie in der Welt der seltsamen Nebenwirkungen und esoterischer Debuggen.

Eine gute Nachricht ist, dass TPL Datenfluß-Blöcke mit Rx sehr schön spielen. Sie haben AsObserver / AsObservable Adapter und Sie können sie in der Mitte der Rx-Pipeline bleiben, wenn nötig. Aber Rx hat viel mehr Muster und Anwendungsfälle. Also meine Faustregel mit Rx und fügen TPL Datenfluss starten je nach Bedarf.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top