¿Cómo se relacionan entre sí el Marco Reactivo, PLINQ, TPL y las extensiones Paralelas?


Al menos desde el lanzamiento de.NET 4.0, Microsoft parece haber puesto mucho esfuerzo en el soporte para la programación paralela y asíncrona y parece que han surgido muchas API y bibliotecas alrededor de esto. Especialmente los siguientes nombres elegantes se mencionan constantemente en todas partes últimamente:

  • Marco reactivo,
  • PLINQ (LINQ paralelo),
  • TPL (Biblioteca paralela de tareas) y
  • Extensiones Paralelas.

Ahora todos parecen ser productos de Microsoft y todos parecen apuntar a escenarios de programación asíncrona o paralela para. NET. Pero no está muy claro qué es realmente cada uno de ellos y cómo están relacionados entre sí. Algunos podrían ser lo mismo.

En pocas palabras, ¿puede alguien aclarar qué es qué?

Author: bitbonk, 2010-01-26

2 answers

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

Por ejemplo, digamos que tienes un montón de cadenas y quieres obtener todas las que comienzan con la letra "A". Puedes escribir tu consulta así:

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

Y esto funciona fino. Sin embargo, si tuviera 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 regular en una paralela que se ejecute en varios núcleos. Bastante limpio.


El TPL (Biblioteca Paralela de Tareas) es una especie de complemento de PLINQ, y juntos forman Extensiones Paralelas. Mientras que PLINQ se basa en gran medida en un funcional estilo de programación con no efectos secundarios, los efectos secundarios son precisamente para lo que está el TPL. Si quieres realmente trabajar en paralelo en lugar de simplemente buscar/seleccionar cosas en paralelo, utiliza el TPL.

El TPL es esencialmente la clase Parallel que expone sobrecargas de For, Foreach, y Invoke. Invoke es un poco como hacer cola de tareas en el ThreadPool, pero un poco más simple de usar. IMO, los bits más interesantes son el For y Foreach. Por ejemplo, digamos que tienes un montón de archivos que quieres comprimir. Usted podría escribir la versión secuencial regular:

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 de nuevo, 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 terminará a la mitad o 1/4 de la vez.

La ventaja de esto sobre simplemente tirarlo todo en el ThreadPool es que esto en realidad se ejecuta sincrónicamente. Si usaras ThreadPool en su lugar (o simplemente Thread instancias), tendrías que encontrar una manera de averiguar cuándo todas las tareas están terminadas, y aunque esto no es terriblemente complicado, es algo con lo que mucha gente tiende a meter la pata o al menos tiene problemas. Cuando usas la clase Parallel, no tienes que pensar sobre ello; el aspecto de multi-threading está oculto para ti, todo se maneja detrás de las escenas.


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 en esto, pero para hacer una larga historia corta, en lugar de conectar los controladores de eventos a los eventos, Rx le permite tratar las secuencias de eventos como... bueno, secuencias (IEnumerable<T>). Puedes procesar eventos de manera iterativa en lugar de dispararlos asincrónicamente en momentos aleatorios, donde tienes que guardar estado todo el tiempo para detectar una serie de eventos que ocurren en un orden particular.

Uno de los mejores ejemplos que he encontrado de Rx es aquí. Vaya a la sección" Linq to IObservable " donde implementa un controlador de arrastrar y soltar, que normalmente es un dolor en WPF, en solo 4 líneas de código. Rx te da composición de 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 puede incluir en cualquier lugar.


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

 93
Author: Aaronaught,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-30 03:31:57

Me gusta la respuesta de Aaronaght, pero diría que Rx y TPL resuelven diferentes problemas. Parte de lo que el equipo de TPL agregó son las primitivas de roscado y 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 características primitivas y de tiempo de ejecución.

Pero el TPL y el 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 para 'reaccionar' a los datos de un flujo (como la entrada del ratón o cuando se recibe un flujo de mensajes relacionados de 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 sobre la cantidad total de trabajo, el trabajo se puede dividir en trozos de un cierto tamaño (Tareas), y en el caso de hacer cálculos sobre una jerarquía las tareas se pueden "encadenar" 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 en la plomería, como la cancelación (vea el video del Canal 9 en CancellationTokenSource). TPL también tiene muchos botones para dominios especializados como el procesamiento de datos casi en tiempo real.

Rx será lo que la mayoría de los desarrolladores deberían terminar usando. Es cómo las aplicaciones WPF pueden 'reaccionar' a mensajes externos como datos externos (flujo de mensajes de mensajería instantánea a un cliente de mensajería instantánea) o entrada externa (como el ejemplo de arrastre del ratón vinculado desde Aaronaght). Bajo las cubiertas Rx utiliza primitivas de threading de TPL / BCL, colecciones threadsafe de TPL / BCL y objetos de tiempo de ejecución como ThreadPool. En mi mente, Rx es el' nivel más alto ' de programación para expresar tus intenciones.

Todavía está por verse si el desarrollador promedio puede envolverse en el conjunto de intenciones que puede expresar con Rx. :)

Pero creo que el próximo par de años, el TPL vs Rx va a ser el próximo debate como LINQ to SQL vs Marco de la Entidad. Hay dos tipos de API en el mismo dominio y están especializados para diferentes escenarios, pero se superponen de muchas maneras. Pero en el caso de TPL y Rx, en realidad son conscientes el uno del otro y hay adaptadores incorporados para componer aplicaciones y usar ambos marcos juntos (como alimentar los resultados de un bucle PLINQ en un flujo Rx IObservable). Para la gente que no ha hecho ninguna programación paralela hay un montón de aprender a ponerse al día.

Actualización: He estado usando TPL y RxNet en mi trabajo regular durante los últimos 6 meses (de los 18 meses desde mi respuesta original). Mis pensamientos de 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

 28
Author: yzorg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-10 03:44:07