asynchronous - tiempo - ¿Por qué no debería usar F#flujos de trabajo asíncronos para el paralelismo?
task c# ejemplo (3)
He estado aprendiendo F # recientemente, y estoy particularmente interesado en su facilidad para explotar el paralelismo de datos. El idioma de los data |> Array.map |> Async.Parallel |> Async.RunSynchronously
parece muy fácil de entender y sencillo de usar y obtener un valor real.
Entonces, ¿por qué async
no es realmente para esto? El mismo Donald Syme dice que PLINQ y Futuros son probablemente una mejor opción. Y otras respuestas que he leído aquí concuerdan con eso y también recomiendan TPL. (PLINQ no parece ser demasiado diferente de las funciones integradas anteriores, siempre y cuando use el F # Powerpack para obtener las funciones PSeq
).
F # y los lenguajes funcionales tienen mucho sentido para esto, y algunas aplicaciones han logrado un gran éxito con el paralelismo async
.
Entonces, ¿por qué no debería usar async
para ejecutar procesos de datos paralelos? ¿Qué voy a perder si escribo un código async
paralelo en lugar de usar PLINQ o TPL?
Escribí un artículo que implementa nuevamente una muestra de C # TPL usando tanto Task
como Async
, que también tiene algunos comentarios sobre la diferencia entre los dos. Puede encontrarlo aquí y también hay una versión basada en async más avanzada .
Aquí hay una cita del primer artículo que compara las dos opciones:
La elección entre las dos posibles implementaciones depende de muchos factores. Los flujos de trabajo asincrónicos se diseñaron específicamente para F #, por lo que se ajustan mejor al lenguaje. Ofrecen un mejor rendimiento para las tareas vinculadas de E / S y proporcionan un manejo de excepciones más conveniente. Además, la sintaxis secuencial es bastante conveniente. Por otro lado, las tareas se optimizan para los cálculos de CPU vinculados y hacen que sea más fácil acceder al resultado del cálculo desde otros lugares de la aplicación sin caché explícito.
Entonces, ¿por qué no debería usar async para ejecutar procesos de datos paralelos?
Si tiene una pequeña cantidad de tareas no async
completamente independientes y muchos núcleos, no hay nada de malo en usar asincrónico para lograr el paralelismo. Sin embargo, si sus tareas son dependientes de alguna manera o si tiene más tareas que núcleos o si utiliza demasiado async
en el código, dejará mucho rendimiento sobre la mesa y podría hacerlo mucho mejor al elegir un una base más apropiada para la programación paralela.
Tenga en cuenta que su ejemplo se puede escribir aún más elegantemente utilizando el TPL de F #, aunque:
Array.Parallel.map f xs
¿Qué voy a perder si escribo un código asincrónico paralelo en lugar de usar PLINQ o TPL?
Se pierde la capacidad de escribir código inconsistente de caché y, en consecuencia, sufrirá muchos errores de caché y, por lo tanto, todos los núcleos se estancan esperando la memoria compartida, lo que significa escasa escalabilidad en un multinúcleo.
El TPL se basa en la idea de que las tareas secundarias deben ejecutarse en el mismo núcleo que sus padres con una alta probabilidad y, por lo tanto, se beneficiará al reutilizar los mismos datos porque estarán calientes en la memoria caché local de la CPU. No hay tal seguridad con asincronización.
Siempre pensé que era lo que TPL, PLinq, etc. te daban más de lo que hace Async. (Me viene a la mente el mecanismo de cancelación.) Esta pregunta tiene algunas respuestas mejores.
Este artículo sugiere una ligera ventaja de rendimiento para TPL, pero probablemente no lo suficiente como para ser significativo.