system.reactive plinq parallel-extensions task-parallel-library

system.reactive - ¿Cómo se relacionan Reactive Framework, PLINQ, TPL y las extensiones paralelas?



parallel-extensions task-parallel-library (2)

Al menos desde el lanzamiento de .NET 4.0, Microsoft parece haber puesto mucho esfuerzo en el apoyo de la programación paralela y asincrónica, y parece que han surgido muchas API y bibliotecas al respecto. Especialmente los siguientes nombres elegantes se mencionan constantemente en todas partes últimamente:

  • Marco reactivo,
  • PLINQ (LINQ paralelo),
  • TPL (Task Parallel Library) y
  • Extensiones Paralelas.

Ahora todos parecen ser productos de Microsoft y todos parecen apuntar a escenarios de programación asincrónicos o paralelos para .NET. Pero no está del todo claro qué es cada uno de ellos en realidad y cómo se relacionan entre sí. Algunos podrían ser lo mismo.

En pocas palabras, ¿alguien puede dejar las cosas claras en qué es qué?


Me gusta la respuesta de Aaronaught, pero diría que Rx y TPL resuelven diferentes problemas. Parte de lo que el equipo de TPL agregó son las primitivas de subprocesamiento y las mejoras significativas a los bloques de construcción del tiempo de ejecución como el ThreadPool. Y todo lo que enumera está construido sobre estas primitivas y características de tiempo de ejecución.

Pero el TPL y Rx resuelven dos problemas diferentes. TPL funciona mejor cuando el programa o algoritmo está ''tirando y haciendo cola''. Rx sobresale cuando el programa o algoritmo necesita ''reaccionar'' a los datos de una secuencia (como la entrada del mouse o cuando recibe una secuencia de mensajes relacionados desde un punto final como WCF).

Necesitaría el concepto de ''unidad de trabajo'' de TPL para trabajar como el sistema de archivos, iterar sobre una colección o recorrer una jerarquía como un organigrama. En cada uno de esos casos, el programador puede razonar acerca de la cantidad total de trabajo, el trabajo se puede dividir en trozos de cierto tamaño (Tareas) y, en el caso de hacer cálculos sobre una jerarquía, las tareas pueden "encadenarse" juntas. . Por lo tanto, ciertos tipos de trabajo se prestan al modelo de "jerarquía de tareas" de TPL y se benefician de las mejoras de la cancelación de fontanería (consulte el video del Canal 9 en CancellationTokenSource). TPL también tiene muchos mandos para dominios especializados, como el procesamiento de datos casi en tiempo real.

Rx será lo que la mayoría de los desarrolladores deberían usar. Es la forma en que las aplicaciones WPF pueden ''reaccionar'' a mensajes externos como datos externos (transmisión de mensajes de IM a un cliente de mensajería instantánea) o entrada externa (como el ejemplo de arrastre del mouse enlazado desde Aaronaught). Debajo de las carátulas, Rx utiliza primitivas de subprocesamiento de TPL / BCL, colecciones de subprocesos de TPL / BCL y objetos de tiempo de ejecución como ThreadPool. En mi opinión, Rx es el programa de "más alto nivel" para expresar tus intenciones.

Aún no se ha visto si el desarrollador promedio puede entender su conjunto de intenciones que puede expresar con Rx. :)

Pero creo que en los próximos años el TPL vs. Rx va a ser el próximo debate como LINQ-to-SQL vs. Entity Framework. Hay dos formas de API en el mismo dominio y están especializadas para diferentes escenarios, pero se superponen de muchas maneras. Pero en el caso de TPL & Rx, en realidad son conscientes el uno del otro y hay adaptadores incorporados para componer aplicaciones y utilizar ambos marcos juntos (como la alimentación de resultados de un bucle PLINQ en un flujo IObservable Rx). Para las personas que no han hecho ninguna programación paralela, hay una gran cantidad de aprendizaje para ponerse al día.

Actualización: he estado usando TPL y RxNet en mi trabajo habitual durante los últimos 6 meses (de los 18 meses desde mi respuesta original). Mi opinión sobre la elección de TPL y / o RxNet en un servicio WCF de nivel medio (servicio LOB empresarial): http://yzorgsoft.blogspot.com/2011/09/middle-tier-tpl-andor-rxnet.html


PLINQ (Parallel Linq) es simplemente una nueva forma de escribir consultas regulares de Linq para que se ejecuten en paralelo; en otras palabras, el Framework se ocupará automáticamente de ejecutar su consulta a través de múltiples hilos para que terminen más rápido (es decir, utilizando múltiples núcleos de CPU )

Por ejemplo, supongamos que tiene un montón de cadenas y desea obtener todas las que comienzan con la letra "A". Podrías escribir tu consulta así:

var words = new[] { "Apple", "Banana", "Coconut", "Anvil" }; var myWords = words.Select(s => s.StartsWith("A"));

Y esto funciona bien Sin embargo, si tenía 50,000 palabras para buscar, es posible que desee aprovechar el hecho de que cada prueba es independiente y dividir esto en varios núcleos:

var myWords = words.AsParallel().Select(s => s.StartsWith("A"));

Eso es todo lo que tiene que hacer para convertir una consulta normal en una paralela que se ejecuta en múltiples núcleos. Con buena pinta.

El TPL (Task Parallel Library) es una especie de complemento de PLINQ, y juntos forman Extensiones Paralelas. Mientras que PLINQ se basa principalmente en un estilo funcional de programación sin efectos secundarios, los efectos secundarios son precisamente para lo que es el TPL. Si desea realizar un trabajo en paralelo en lugar de solo buscar / seleccionar cosas en paralelo, use el TPL.

El TPL es esencialmente la clase Parallel que expone las sobrecargas de For , Foreach e Invoke . Invoke es como cola de tareas en el ThreadPool , pero un poco más simple de usar. OMI, los bits más interesantes son For y Foreach . Entonces, por ejemplo, digamos que tiene un montón de archivos que desea comprimir. Puede escribir la versión secuencial normal:

string[] fileNames = (...); foreach (string fileName in fileNames) { byte[] data = File.ReadAllBytes(fileName); byte[] compressedData = Compress(data); string outputFileName = Path.ChangeExtension(fileName, ".zip"); File.WriteAllBytes(outputFileName, compressedData); }

De nuevo, cada iteración de esta compresión es completamente independiente de cualquier otra. Podemos acelerar esto haciendo varios de ellos a la vez:

Parallel.ForEach(fileNames, fileName => { byte[] data = File.ReadAllBytes(fileName); byte[] compressedData = Compress(data); string outputFileName = Path.ChangeExtension(fileName, ".zip"); File.WriteAllBytes(outputFileName, compressedData); });

Y nuevamente, eso es todo lo que se necesita para paralelizar esta operación. Ahora cuando ejecutamos nuestro método CompressFiles (o como decidamos llamarlo), usará múltiples núcleos de CPU y probablemente termine a la mitad o 1/4 del tiempo.

La ventaja de esto más que ThreadPool todo en el ThreadPool es que esto realmente se ejecuta sincrónicamente . Si usó ThreadPool en ThreadPool lugar (o simplemente instancias de ThreadPool ), tendría que encontrar una manera de averiguar cuándo terminaron todas las tareas, y aunque esto no es demasiado complicado, es algo que muchos la gente tiende a meter la pata o al menos tiene problemas con. Cuando usas la clase Parallel , realmente no tienes que pensar en eso; el aspecto de multi-threading está oculto para usted, todo se maneja detrás de escena.

Las extensiones reactivas (Rx) son realmente una bestia completamente diferente. Es una forma diferente de pensar sobre el manejo de eventos. Realmente hay mucho material para cubrir sobre esto, pero para IEnumerable<T> , en lugar de conectar controladores de eventos a eventos, Rx te permite tratar secuencias de eventos como ... bueno, secuencias ( IEnumerable<T> ). Puede procesar los eventos de forma iterativa en lugar de tenerlos activados de forma asincrónica en momentos aleatorios, donde debe mantener el estado de ahorro todo el tiempo para detectar una serie de eventos que suceden en un orden determinado.

Uno de los mejores ejemplos que he encontrado de Rx está here . Vaya a la sección "Linq to IObservable" donde implementa un controlador de arrastrar y soltar, que normalmente es un problema en WPF, en solo 4 líneas de código. Rx te ofrece la composición de los eventos, algo que realmente no tienes con los controladores de eventos regulares, y los fragmentos de código como estos también son fáciles de refactorizar en clases de comportamiento que puedes usar en cualquier lugar.

Y eso es. Estas son algunas de las características más geniales que están disponibles en .NET 4.0. ¡Hay muchos más, por supuesto, pero estos fueron los que usted preguntó!