2010-02-01 12 views
8

Cuando sale F #, voy a tener una vergüenza de riquezas en el área de programación asincrónica/paralela. Un answer to this question hace un buen trabajo al describir las diferencias entre Tareas, Parallel LINQ y Reactive Framework, pero me preguntaba cómo encajan los flujos de trabajo asincrónicos en la imagen, exactamente.F #: Asynch y tareas y PLINQ, ¡oh mi!

Corrígeme si me equivoco, pero según entiendo, los flujos de trabajo de asincronización serán la forma más fácil de trabajar con operaciones vinculadas a IO, especialmente aquellas que tienen un método AsynchXxx definido, o seguir el BeginXxx/EndXxx patrón. Otra ventaja es que los flujos de trabajo de asincronización son compostables y pueden construirse a partir de otros flujos de trabajo de asincronización, lo que permite una gran flexibilidad en la estructura de un programa.

Creo que lo que necesito ayuda es entender bajo qué circunstancias elegiría tareas o PLINQ sobre flujos de trabajo asíncronos, en código F #. Creo que he leído que la Biblioteca de tareas paralelas tiene formas más sofisticadas de equilibrar la carga entre los núcleos. Si eso es cierto, entonces las Tareas podrían ser una mejor opción para las operaciones puramente vinculadas a la CPU que necesitan operar en paralelo. PLINQ, por otro lado, parece ser principalmente una forma conveniente de paralelizar código existente que funciona con secuencias.

Finalmente, asumiendo que mi comprensión de las fortalezas de cada enfoque es correcta, ¿es posible o recomendable combinarlas? Por ejemplo, quizás uno podría componer una serie de operaciones de flujos de trabajo asíncronos y luego transformarlas en Tareas antes de la ejecución. Si eso es posible, o incluso una buena idea.

+0

Hmm, estoy seguro de que puede hacer algo con Async.StartAsTask y Async.AwaitTask – gradbot

Respuesta

12

Ver Task Parallel Library vs Async Workflows.

me gustaría resumir los conceptos básicos de la siguiente manera:

tareas de la Biblioteca paralelo: Permite varias unidades de trabajo a ejecutar de manera eficiente en múltiples núcleos, incluyendo escenarios relativamente simples, tales como el desove varios subprocesos para hacer cálculos similares en paralelo así como operaciones más complicadas donde los cálculos mismos también terminan generando tareas adicionales. Utiliza el hilo de rosca de .NET 4.0 mejorado y las colas de robo de trabajo para garantizar que todos los núcleos se mantengan ocupados.

Flujos de trabajo asincrónicos: Permite que los cálculos asíncronos se ejecuten sin ocupar hilos innecesarios, iniciando devoluciones de llamada cuando los resultados están disponibles.

PLINQ: código escrito usando PLINQ termina corriendo a través de la TPL, pero esta es una interfaz más agradable para el código que se expresa fácilmente mediante consultas LINQ (por ejemplo, haciendo una sola operación en cada elemento de una matriz de datos en paralelo)

Tenga en cuenta que los flujos de trabajo asincrónicos se pueden convertir en las tareas utilizando el método StartAsTask y tareas pueden ser convertidos en Async s utilizando el método Async.AwaitTask, por lo que es posible tender un puente sobre las tecnologías, a pesar de que no tienen por objeto ligeramente diferentes escenarios de destino.

Para mí, la regla de oro sería que si está realizando activamente muchos cálculos en diferentes subprocesos, querrá usar el TPL (posiblemente mediante PLINQ o un equivalente de F # como el módulo PSeq), mientras que si intenta hacer mucho IO (ya sea en paralelo o no), debe usar flujos de trabajo de asincronización. Entonces, un raytracer usaría TPL para iniciar tareas para renderizar cada píxel (o línea de exploración) en paralelo, lo que maximizaría la potencia de cómputo disponible en su computadora. Pero la descarga de un montón de páginas web se haría con flujos de trabajo asíncronos, ya que no hay mucho cómputo para distribuir entre núcleos; solo necesita que el SO le notifique cuando aparezcan los resultados.

+0

Interesante, gracias. Entonces, si tuviera una razón sensata para descargar un montón de páginas web, y luego iniciar un rastreador basado en los datos, ¿sería mejor tener un paso asíncrono seguido de un paso de la tarea, o usar 'StartAsTask' para convertir el asincroniza las llamadas a una tarea que realiza llamadas asincrónicas y luego genera más tareas? –

+0

@Joel: Probablemente valdría la pena perfilar cada opción para ver cuál funciona mejor, pero no esperaría mucha diferencia de ninguna manera. Eventualmente, todas las tareas se ejecutarán contra el mismo grupo de subprocesos, por lo que creo que no importa si provienen de diferentes bloques 'async', en cuyo caso es realmente una preferencia personal. Al mismo tiempo, podría haber algún tipo de interacción sutil que me falta, por lo que vale la pena intentarlo de ambas maneras por las dudas. – kvb

1

Los flujos de trabajo asincrónicos se implementan a través de la sintaxis monódica F #. Esto significa que en lugar de transformar sus flujos de trabajo en tareas, podría escribir su propia versión de "asincronización" basada en la biblioteca de tareas paralelas. Lo digo con un par de advertencias:

  • Sería difícil de hacer.
  • Las opertaciones asincrónicas que usan el patrón BeginXxx/EndXxx en .NET registran devoluciones de llamadas en el grupo de subprocesos. No estoy seguro de que pueda cambiar esto, para redirigirlos a usar tareas en su lugar.

Para obtener más información sobre cómo implementar una mónada en F #, consulte el libro "Expert F #" o google un poco en "Minas F #".

No es una respuesta completa. Lo sé, pero espero que ayude un poco.

+0

Bien, así que no hay una forma sencilla de transición entre flujos de trabajo asincrónicos y Tareas. Bueno saber. ¿Alguien tiene un comentario sobre cómo saber cuándo usar tareas en lugar de flujos de trabajo asincrónicos? –

+0

En realidad, está lejos de transformarse entre uno y otro, vea @kvb answer. Mis respuestas son más que nada que podría hacer si tuviera ganas de experimentar. – Robert