2010-03-30 13 views
36

¿Cuándo se elegiría usar Rx sobre TPL o son los 2 marcos ortogonales?TPL vs Reactive Framework

Por lo que entiendo, Rx está destinado principalmente a proporcionar una abstracción sobre los eventos y permitir la composición, pero también permite proporcionar una abstracción sobre las operaciones asincrónicas. utilizando las sobrecargas Createxx y las sobrecargas y cancelaciones de Fromxxx mediante la eliminación del IDisposable devuelto.

TPL también proporciona una abstracción para las operaciones a través de tareas y capacidades de cancelación.

Mi dilema es cuándo usar qué y para qué escenarios?

+0

enlace a mayores, cerrado, pregunta duplicado: http://stackoverflow.com/questions/2138361/reactive-framework-vs-plinq-vs-task-parallel-library-vs-parallel-extensions/2188259 – yzorg

Respuesta

39

El propósito principal de Rx no es proporcionar una abstracción sobre los eventos. Este es solo uno de sus resultados. Su objetivo principal es proporcionar un modelo de empuje composable para colecciones.

El marco reactivo (Rx) se basa en IObservable<T> siendo el matemático dual de IEnumerable<T>. Entonces, en lugar de "extraer" elementos de una colección usando IEnumerable<T>, podemos tener objetos "empujados" a través del IObservable<T>.

Por supuesto, cuando realmente buscamos fuentes observables cosas como eventos & operaciones asincrónicas son candidatos excelentes.

El marco reactivo, naturalmente, requiere un modelo de subprocesos múltiples para poder ver las fuentes de datos observables y para gestionar consultas y suscripciones. Rx hace un uso intensivo del TPL para hacer esto.

De modo que si utiliza Rx está utilizando implícitamente el TPL.

Utilizaría el TPL directamente si desea un control directo sobre sus tareas.

Pero si tiene fuentes de datos que desea observar y realizar consultas en contra, recomiendo totalmente el marco reactivo.

+2

lo haría Por ejemplo, si dejas de lado las preocupaciones, las frases "proporcionar una abstracción sobre los eventos" son equivalentes a "modelo push para colecciones de objetos de eventos (también conocidos como objetos DTO)". – yzorg

+3

Muy buena respuesta, y en aplicaciones prácticas es en gran parte cierto. Sin embargo, Rx se puede usar sin el TPL en absoluto. También se puede utilizar Rx en una aplicación de subproceso completamente único sin ninguna concurrencia en absoluto (al igual que WPF o NodeJS logran la asincronía en un único subproceso). Me gusta mucho el tono de su ascensor, espero la última palabra, diría "Su objetivo principal es proporcionar un modelo de empuje composable para _secuencias de datos_". He descubierto que mientras más rápido los desarrolladores piensen en secuencias en lugar de colecciones, más rápido asimilarán Rx. –

23

Algunas pautas Me gusta seguir:

  • estoy tratando con los datos que no sean originarios. ¿Datos que llegan cuando les da la gana? Entonces RX.
  • ¿Estoy originando cálculos y necesito administrar la concurrencia? Entonces TPL.
  • ¿Administro múltiples resultados y debo elegirlos según el tiempo? Entonces RX.
11

Me gusta Scott W's bullet points. Para poner algunos ejemplos más concretos en los mapas Rx muy bien a

  • consumo arroyos
  • la realización de trabajos de no bloqueo asíncrono como las peticiones web.
  • eventos de transmisión (cualquiera.eventos en red, como eventos de tipo de mensaje movimiento del ratón OR Servicio Bus)
  • Composición "corrientes" en los eventos juntos
  • operaciones de estilo Linq
  • La exposición de los flujos de datos de su API pública

TPL parece trazar muy bien a

  • paralelización interna del trabajo
  • realizar sin bloqueo de trabajo asíncrono como una tela solicita
  • que realizan los flujos de trabajo y las continuaciones

Una cosa que he notado con IObservable (Rx) es que se convierte en omnipresente. Una vez que esté en su base de código, ya que sin duda estará expuesto a través de otras interfaces, finalmente aparecerá en toda su aplicación. Me imagino que esto puede ser aterrador al principio, pero la mayoría del equipo se siente bastante cómodo con Rx ahora y adora la cantidad de trabajo que nos ahorra.

IMHO Rx será la biblioteca dominante sobre el TPL, ya que es compatible con .NET 3.5, 4.0, Silverlight 3, Silverlight 4 y Javascript. Esto significa que efectivamente debe aprender un estilo y es aplicable a muchas plataformas.

EDITAR: He cambiado de opinión acerca de Rx ser dominante sobre TPL. Resuelven diferentes problemas, por lo que no deberían ser comparados de esa manera. Con .NET 4.5/C# 5.0 las palabras clave async/await nos vincularán aún más al TPL (lo cual es bueno). Para una profunda discuson en Rx vs eventos vs TPL etc. echa un vistazo a la first chapter de mi libro en línea IntroToRx.com

9

Actualización, Diciembre 2016: Si usted tiene 30 minutos, le recomiendo que lea relato de primera mano de Joe Duffy en lugar de mi especulación Creo que mi análisis se mantiene bien, pero si ha encontrado esta pregunta, le recomiendo que vea la publicación del blog en lugar de estas respuestas porque, además de TPL vs Rx.NET, también cubre proyectos de investigación de MS (Midori, Cosmos).

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


creo MS cometió un gran error sobre-corregir después de .NET 2.0 salió. Introdujeron muchas API de administración de concurrencia diferentes, todas al mismo tiempo, desde diferentes partes de la empresa.

  • Steven Toub estaba empujando duro para las primitivas compatibles con el proceso para reemplazar eventos (que comenzó como Future<T> y se convirtió en Task<T>)
  • Investigación MS tenía MIN-LINQ y extensiones reactivas (Rx)
  • Hardware/Embedded tenido robotics cuntime (CCR)

Mientras tanto muchos equipos de API administradas estaban tratando de vivir con APM y Threadpool.QueueUserWorkItem(), sin saber si Toub ganaría su lucha para enviar Future<T>/Task<T> en mscorlib.dll. Al final parece que tienen cobertura, y enviaron Task<T> y IObservable<T> en mscorlib, pero no permitieron ninguna otra API de Rx (ni siquiera ISubject<T>) en mscorlib.Creo que este seto terminó causando una gran cantidad de duplicaciones (más adelante) y un esfuerzo desperdiciado dentro y fuera de la empresa.

para la duplicación, véase: Task vs IObservable<Unit>, Task<T> vs AsyncSubject<T>, Task.Run() vs Observable.Start(). Y esto es solo la punta del iceberg. Pero a un nivel más alto en cuenta:

  • StreamInsight - flujos de eventos de SQL, optimizado de código nativo, pero las consultas de eventos definidos usando la sintaxis de LINQ
  • TPL flujo de datos - construido sobre TPL, construido en paralelo a Rx, optimizado para ajustar el paralelismo de subprocesos, no es bueno en la composición de consultas
  • Rx - Increíble expresividad, pero cargada de peligros. Mezcla streams 'calientes' con los métodos de extensión de estilo IEnumerable, lo que significa que bloqueas muy fácilmente para siempre (llamar al First() en una transmisión en caliente nunca regresa). Los límites de programación (limitación del paralelismo) se realizan a través de métodos de extensión SubscribeOn() bastante extraños, que son extrañamente implícitos y difíciles de corregir. Si comienza a aprender Rx reserve un largo tiempo para aprender todos los peligros que debe evitar. Pero Rx es realmente la única opción para componer secuencias de eventos complejos o necesita un filtrado/consulta complejos.

No creo que Rx tenga una oportunidad de luchar en la amplia adopción hasta que MS envíe ISubject<T> en mscorlib. Lo cual es triste, porque Rx contiene algunos tipos concretos (genéricos) muy útiles, como TimeInterval<T> y Timestamped<T>, que creo que deberían estar en Core/mscorlib como Nullable<T>. Además, System.Reactive.EventPattern<TEventArgs>.

+1

Error ortográfico hilarante. –

+1

@DaveSexton IObservalbe? – yzorg

+1

Creo que @DaveSexton significaba SteamInsight. Pero en una nota seria, ¡gracias por el análisis más insigtuoso de los marcos! ¡Esta IMO debería haber sido la respuesta aceptada! – kkm

0

Hice una aplicación para Windows Phone. Comenzó con RX. El problema fue que en algún momento utilicé una nueva versión de RX y ¿adivinen qué? Muchas funciones obtuvieron el atributo "obsoleto". Entonces comencé con TPL y ahora tengo un proyecto mixto con ambos. Mi consejo es que si utilizas muchas llamadas web asíncronas, es mejor usar TPL. Como ya se ha escrito, RX está usando TPL, ¿por qué no usar TPL desde el principio?

+0

Uno de los principales beneficios de Rx es que async el código se vuelve mucho más fácil de escribir y seguir. Con TPL terminarías lidiando con devoluciones de llamada anidadas haciendo que el código sea difícil de seguir y depurar. El equipo de Rx habría presentado llamadas "equivalentes" para las llamadas "obsoletas". ¿Ha recomendado MSDN para las llamadas obsoletas para encontrar sus nuevos equivalentes? –

+0

Volveré a escribir mi Aplicación como Aplicación Universal y usaré la aplicación PRISM de referencia AdventureWorksShopper como línea de base. Lo que puedo ver en esta aplicación es que la arquitectura es muy buena y que todas las funcionalidades de RX están disponibles en TPL, por lo que ya no se necesita RX. No creo que TPL sea más difícil de leer que RX, la curva de aprendizaje es la misma. Lo que quiero es un marco a prueba de futuro. No me gusta obsoleto. Obsoleto significa: ya no tenemos el dinero para respaldarlo. De todos modos, eso es lo que pienso. –

4

Diría que TPL Dataflow cubre un subconjunto especializado de funcionalidad en Rx. El flujo de datos es para el procesamiento de datos, que puede tomar una cantidad medible de tiempo, mientras que Rx es para eventos, como la posición del mouse, estados de error, etc. donde el tiempo de manipulación es insignificante.

Ejemplo: su controlador "suscribir" es asincrónico y no desea tener más de 1 ejecutor en ese momento. Con Rx tienes que bloquear, no hay otra forma de evitarlo, porque Rx es asíncrona y no amenaza asincrónica de manera especial en muchos lugares.

.Subscribe(myAsyncHandler().Result) 

Si no bloquear, entonces Rx considerará que la acción es completa, mientras manejador todavía se está ejecutando de forma asíncrona.

Se podría pensar que si lo hace

.ObserveOn(Scheduler.EventLoopSchedule) 

de problema está resuelto. Pero esto romperá su flujo de trabajo .Complete(), porque Rx pensará que se realizará tan pronto como programe la ejecución y saldrá de la aplicación sin esperar a que se complete la operación asincrónica.

Si no desea permitir más de 4 tareas simultáneas simultáneas, Rx no ofrece nada de fábrica. Quizás pueda piratear algo implementando su propio programador, búfer, etc.

TPL Dataflow ofrece una solución muy buena en ActionBlock.Puede limitar las acciones simultáneas a cierto número y comprende las operaciones asincrónicas, de modo que al llamar a Complete() ya la espera de Completed hará exactamente lo que cabría esperar: esperar a que se completen todas las tareas asincrónicas en progreso.

Otra característica que tiene TPL es "contrapresión". Digamos que descubrió un error en su rutina de manejo y necesita recalcular los datos del mes pasado. Si se suscribe a su fuente utilizando Rx, y su canalización contiene búferes ilimitados u ObserveOn, se le agotará la memoria en cuestión de segundos porque la fuente seguirá leyendo más rápido de lo que el procesamiento puede manejar. Incluso si implementa el bloqueo de los consumidores, su fuente puede sufrir bloqueos de llamadas, por ejemplo, si la fuente es asincrónica. En TPL puede implementar el código fuente como

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

que no bloquea la fuente aún mientras el controlador está sobrecargado.

En general, encontré que Rx es adecuado para acciones que son lentas y computacionalmente livianas. Si el tiempo de procesamiento se vuelve sustancial, se encuentra en el mundo de los extraños efectos secundarios y la depuración esotérica.

La buena noticia es que los bloques TPL Dataflow funcionan muy bien con Rx. Tienen adaptadores AsObserver/AsObservable y puede colocarlos en el medio de la tubería Rx cuando sea necesario. Pero Rx tiene muchos más patrones y casos de uso. Así que mi regla de oro es comenzar con Rx y agregar TPL Dataflow según sea necesario.