Question

Quand choisirait-on utiliser Rx sur TPL ou sont les 2 cadres orthogonaux?

D'après ce que je comprends Rx est principalement destinée à une abstraction sur les événements et permettre à la composition, mais il permet aussi de fournir une abstraction sur les opérations asynchrones. en utilisant les surcharges et les surcharges Createxx Fromxxx et l'annulation par la disposition de la IDisposable retourné.

TPL fournit également une abstraction pour les opérations via les capacités des tâches et d'annulation.

Mon dilemme est quand utiliser qui et pour quels scénarios?

Était-ce utile?

La solution

Le but principal de Rx est de ne pas fournir une abstraction sur les événements. Ceci est juste l'un de ses résultats. Son principal objectif est de fournir un modèle push composable pour les collections.

Le cadre réactif (Rx) sont basées sur le IObservable<T> étant le double de IEnumerable<T> mathématique. Ainsi, plutôt que des éléments « tirer » d'une collection à l'aide IEnumerable<T> nous pouvons avoir des objets « poussés » à nous par IObservable<T>.

Bien sûr, quand nous allons réellement chercher des sources observables des choses comme des événements et opérations async sont d'excellents candidats.

Le cadre réactif nécessite naturellement un modèle multi-thread pour pouvoir regarder les sources de données observables et de gérer les requêtes et les abonnements. Rx fait en fait un usage intensif de la TPL pour le faire.

Donc, si vous utilisez Rx vous utilisez implicitement la TPL.

Vous utilisez le TPL directement si vous souhaitez un contrôle direct sur vos tâches.

Mais si vous avez des sources de données que vous souhaitez observer et effectuer des requêtes contre je recommande vivement le cadre réactif.

Autres conseils

Quelques directives J'aime suivre:

  • Suis-je traiter les données que je ne proviennent pas. Les données qui arrive quand il veut? Ensuite RX.
  • Suis-je besoin d'origine des calculs et de gérer la concurrence? Puis TPL.
  • Suis-je gère plusieurs résultats, et doivent choisir parmi eux en fonction du temps? Ensuite RX.

J'aime les points de balle de Scott W. Pour mettre des exemples plus concrets Rx cartes vraiment bien à

  • flux de consommation
  • effectuer des travaux async non bloquante comme les requêtes Web.
  • événements de diffusion en continu (soit des événements .net comme mouvement de souris ou service événements de type de message Bus)
  • "flux" Composing d'événements ensemble
  • opérations de style Linq
  • L'exposition des flux de données à partir de votre API publique

TPL semble bien à la carte

  • parallélisation interne du travail
  • effectuer des travaux async non bloquant comme les requêtes Web
  • effectuant des flux de travail et continuations

Une chose que j'ai remarqué avec IObservable (Rx) est qu'il devient omniprésente. Une fois dans votre base de code, car il sera sans aucun doute être exposé par d'autres interfaces, il apparaît finalement partout dans votre application. J'imagine que cela peut être effrayant au début, mais la plupart de l'équipe est assez à l'aise avec Rx maintenant et aime la quantité de travail qu'il nous sauve.

à mon humble avis Rx sera la bibliothèque dominante sur le TPL car il est déjà pris en charge dans .NET 3.5, 4.0, Silverlight 3, Silverlight 4 et Javascript. Cela signifie que vous avez effectivement d'apprendre un style et il est applicable à de nombreuses plates-formes.

EDIT : J'ai changé d'avis à propos de Rx étant dominant sur TPL. Ils résolvent différents problèmes ne devraient donc pas vraiment être comparé comme ça. Avec 4,5 .NET / C # 5.0 async / attendent des mots-clés seront plus nous attacher à la TPL (ce qui est bon). Pour une discuson profonde sur Rx vs vs événements TPL etc. consultez le de mon livre en ligne IntroToRx.com

Mise à jour, Décembre 2016: Si vous avez 30 minutes, je vous recommande de lire le compte de première main de Joe Duffy à la place de ma spéculation. Je pense que mon analyse tient bien, mais si vous avez trouvé cette question, je vous recommande vivement voir le billet de blog au lieu de ces réponses car en plus de TPL vs Rx.NET il couvre également des projets de recherche sur la SP (Midori, Cosmos).

http://joeduffyblog.com/2016/ 11/30/15-ans-de-concurrency /


Je pense que MS a fait une grosse erreur sur correction après .NET 2.0 est sorti. Ils ont introduit de nombreuses API de gestion de tous à la concurrence en même temps de différentes parties de la société.

  • Steven Toub poussait dur pour les primitives thread-safe pour remplacer l'événement (qui a commencé comme Future<T> et transformé en Task<T>)
  • MS Research avait MIN-LINQ et Reactive Extensions (Rx)
  • Matériel / intégré a la robotique cuntime (CCR)

En attendant de nombreuses équipes de l'API gérées ont essayé de vivre avec APM et Threadpool.QueueUserWorkItem(), ne sachant pas si Toub allait gagner son combat pour expédier Future<T> / Task<T> dans mscorlib.dll. A la fin, on dirait qu'ils couverts, et expédiés à la fois Task<T> et IObservable<T> dans mscorlib, mais ne permettait pas d'autres API Rx (même pas de ISubject<T>) dans mscorlib. Je pense que cette couverture a fini par causer une énorme quantité de duplication (plus tard) et un gaspillage d'efforts à l'intérieur et à l'extérieur de l'entreprise.

Pour la duplication voir: Task vs IObservable<Unit>, Task<T> contre AsyncSubject<T>, Task.Run() contre Observable.Start(). Et cela est que la pointe de l'iceberg. Mais à un niveau plus élevé compte:

  • StreamInsight - flux d'événements SQL, code-natif optimisé, mais les requêtes d'événements définis en utilisant la syntaxe LINQ
  • TPL Dataflow - construit sur TPL, construit en parallèle à Rx, optimisé pour le parallélisme peaufinage de filetage, pas bon composant requêtes
  • Rx - expressivité incroyable, mais semée d'embûches. Mixes flux de chaleur »avec des méthodes d'extension de style IEnumerable, ce qui signifie bloquer très facilement à jamais (appeler First() sur un courant chaud ne retourne jamais). limites de planification (limitation de parallélisme) se fait par des méthodes d'extension de SubscribeOn() plutôt bizarres, qui sont bizarrement implicites et difficiles à obtenir le droit. Si vous commencez à apprendre réserve Rx beaucoup de temps pour apprendre tous les pièges à éviter. Mais Rx est vraiment la seule option si la composition des flux d'événements complexes ou vous avez besoin de filtrage / complexe interrogation.

Je ne pense pas que Rx a une chance de combat à l'adoption généralisée jusqu'à ce que les navires MS ISubject<T> en mscorlib. Ce qui est triste, parce que Rx contient des types concrets très utiles (génériques), comme TimeInterval<T> et Timestamped<T>, qui je pense devrait être centrale / mscorlib comme Nullable<T>. En outre, System.Reactive.EventPattern<TEventArgs>.

Je dirais que TPL Dataflow couvre sous-ensemble de fonctionnalités spécialisées dans Rx. DataFlow pour le traitement de données qui peut prendre quantité mesurable de temps, alors que Rx est pour des événements tels que la position de la souris, les états d'erreur, etc où le temps de traitement est négligeable.

Exemple: votre gestionnaire « subscribe » est asynchrone et que vous voulez plus de 1 exécuteur à l'époque. Avec Rx vous devez bloquer, il n'y a pas d'autre solution, parce que Rx est agnostique et async ne menace async d'une manière particulière dans de nombreux endroits.

.Subscribe(myAsyncHandler().Result)

Si vous ne bloquez pas, alors Rx considérera que l'action est terminée alors que gestionnaire est toujours en cours d'exécution en mode asynchrone.

Vous pourriez penser que si vous faites

.ObserveOn(Scheduler.EventLoopSchedule)

que problème est résolu. Mais cela va briser votre flux de travail .Complete (), parce que Rx pensera que cela se fasse dès qu'il planifier l'exécution et vous quittez votre application sans attendre la fin de l'opération async.

Si vous souhaitez autoriser un maximum de 4 tâches simultanées que Rx async ne propose rien hors de la boîte. Peut-être que vous pouvez pirater quelque chose en mettant en place votre propre planificateur, tampon, etc.

TPL Dataflow offre une solution très agréable à ActionBlock. Il peut accélérer des actions simultanées certain nombre et il ne comprend async opérations, afin d'appeler complète () et en attente pour Complété fera exactement ce que vous attendez. Attente pour toutes les tâches Async cours pour compléter

Une autre caractéristique est TPL a « contre-pression ». Disons que vous avez découvert une erreur dans votre routine de traitement et que vous devez recalc les données du mois dernier. Si vous êtes abonné à votre source en utilisant Rx et votre pipeline contient des régulateurs, ou non bornées ObserveOn, que vous serez à court de mémoire en quelques secondes, car la source gardera une lecture plus rapide que le traitement peut manipuler. Même si vous implémentez le blocage consommateur, source peut souffrir d'appels de blocage, par exemple, si la source est asynchrone. En TPL, vous pouvez mettre en œuvre comme source

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

qui ne bloque encore la source ne sera pas attendre tout gestionnaire est surchargé.

Dans l'ensemble, je trouve que Rx est bon ajustement pour les actions qui sont le temps et la lumière informatiquement. Si le temps de traitement devient importante, vous êtes dans le monde des effets secondaires étranges et ésotériques débogage.

Les bonnes nouvelles sont que des blocs TPL Dataflow jouent très agréable avec Rx. Ils ont AsObserver / adaptateurs AsObservable et vous pouvez les coller au milieu du pipeline Rx en cas de besoin. Mais Rx a beaucoup plus tendances et les cas d'utilisation. Donc, ma règle de base est de commencer par Rx et ajouter au besoin TPL Dataflow.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top