haskell - vale - programacion funcional vs orientada a objetos
Lenguaje de programación para el paralelismo funcional: F#vs Haskell (7)
La respuesta simple es que debido a que ambos lenguajes tienen un soporte sólido para el paralelismo y la concurrencia, esto no debería ser un factor en su decisión sobre qué idioma usar. Es decir, hay factores mucho más grandes a tener en cuenta para una decisión como esa.
La programación funcional tiene estructuras de datos inmutables y ningún efecto secundario que sea intrínsecamente adecuado para la programación paralela. Investigo cómo explotar el cómputo multinúcleo en un lenguaje funcional y el código de producción objetivo para algunas aplicaciones numéricas.
F # tiene a Microsoft detrás, y sus construcciones paralelas como PLINQ , TPL , Async Workflow han sido bien documentadas y han mostrado algunos potenciales. Sin embargo, la investigación sobre el paralelismo en Haskell es muy activa en este momento, y posee muchas características agradables que aún no han sido respaldadas por F #:
Mi pregunta es ¿qué idioma debería elegir para el paralelismo funcional? Si se elige F #, ¿hay alguna sugerencia para construir lo que tienen actualmente en Haskell?
ACTUALIZAR:
Elegí la respuesta de Simon porque trajo una buena discusión sobre el recolector de basura, la asignación de memoria y la falta de memoria caché. Me apegaré a F #, y creo que estas respuestas son útiles para mí para estudiar el paralelismo funcional.
En primer lugar, estoy de acuerdo con los demás en que no hay una respuesta objetiva.
Sin embargo, creo que la idea del paralelismo funcional está un poco sobrevalorada. Seguramente, puede encontrar fácilmente dependencias de datos en su programa y si está procesando muchos datos, puede usar una biblioteca paralela de datos para paralelizarlos de manera fácil y segura. Sin embargo, esto se puede hacer incluso en C # (usando TPL y PLINQ) si eres un poco cuidadoso con lo que estás escribiendo.
El problema es que la mayoría de los programas no necesitan ser paralelizados, ya que simplemente no hacen suficiente trabajo intensivo de CPU. Por ejemplo, F # async
resuelve (creo) el problema más importante de habilitar la E / S asíncrona, que es la razón de la mayoría de los "bloqueos" en las aplicaciones conectadas. Creo que la popularidad de Node.js demuestra esta importancia bastante bien.
El valor real de los lenguajes funcionales está en la expresividad del lenguaje: usted puede definir fácilmente las abstracciones para su problema, escribir el código de una manera más sucinta que sea más fácil de entender, razonar y probar. Obtienes esto tanto en F # como en Haskell.
Para responder a su pregunta específica sobre el paralelismo, creo que el estado del soporte de paralelismo en F # es más estable (pero luego, soy una persona F #). Puede elegir entre async, TPL y agentes (# inspirados en Erlang) F # (que son todas bibliotecas bastante estables). En el lado de Haskell, todavía hay mucha evolución pasando. El trabajo más reciente tiene solo algunas semanas de antigüedad. También me resulta más fácil utilizar el paralelismo en un lenguaje con un modelo de evaluación claramente especificado, pero eso puede ser solo mi preferencia personal.
La pureza de Haskell significa que hace una clara distinción entre procesamiento paralelo y concurrencia.
Si está buscando acelerar su gran aplicación de procesamiento de datos mediante la distribución del trabajo en múltiples núcleos, entonces quiere un procesamiento paralelo, lo que significa "par" y sus derivados. Mediante el uso cuidadoso de estas construcciones, puede hacer que su función pura intensiva de CPU se ejecute N veces más rápido en N núcleos, mientras que se asegura de que no ha cambiado el significado del código original o introducido no determinismo en su programa.
Por otro lado, si desea que su programa interactúe con múltiples entidades en el mundo exterior, entrelazando comunicaciones de diferentes entidades pero teniendo aún algún grado de recursos compartidos, entonces quiere concurrencia, lo que significa usar "fork" y alguna combinación de STM y TVars. STM le ofrece una buena semántica transaccional, que contribuye en gran medida a eliminar las condiciones de competencia y otros inconvenientes de concurrencia. Sin embargo, debe prestar atención a la frecuencia de colisión y volver a intentar las tasas.
Voy a recibir una votación negativa por esto, pero déjame ser el cascarrabias.
Los lenguajes funcionales son geniales. Cambian la forma en que piensas acerca de los problemas de descomposición, y mapean increíblemente bien ciertos tipos de problemas. Cada programador debe estar familiarizado con al menos un lenguaje de programación funcional. Pero "los lenguajes funcionales son inherentemente buenos para la programación paralela" probablemente no sea la razón por la cual.
Vale la pena señalar que, sin duda, el lenguaje funcional paralelo más exitoso de todos los tiempos, Erlang, utiliza el paso de mensajes completamente estándar para implementar su paralelismo, y la conexión entre su naturaleza funcional y su paralelismo es, en el mejor de los casos, indirecta.
Veinticinco años atrás, había un gran impulso para los lenguajes funcionales, porque el argumento entonces parecía muy atractivo también: los lenguajes funcionales parecían un ajuste natural para las arquitecturas cada vez más paralelas de la época. El argumento era que los compiladores y los tiempos de ejecución automáticamente podrían implementar el paralelismo, debido a la naturaleza libre de efectos secundarios de los lenguajes. SISAL , que incluso entonces podía compilarse en ejecutables de memoria compartida y distribuida (!), Se desarrolló en este momento, al igual que Haskell, al igual que ML, el predecesor de Objective CAML y los otros lenguajes de la familia ML.
Todo esto solo ofrece un poco de perspectiva histórica. Durante literalmente un cuarto de siglo, los defensores del lenguaje funcional, incluyendo algunas de las mentes más brillantes en el campo, han estado diciendo que el día de los lenguajes funcionales en el sol estaba a la vuelta de la esquina, y que va a ser aplicable al paralelismo esa es la aplicación asesina. Y sin embargo, aquí estamos, sin que nadie haya oído hablar de SISAL; y supongo que la mayoría de los lectores de esta publicación piensan en Haskell como un nuevo lenguaje.
Bien podría ser, por supuesto, que ahora con consideraciones multinúcleo las cosas finalmente se han vuelto tan urgentes que los lenguajes funcionales realmente van a brillar, o que este año será el año en que haya algún avance que ni siquiera puedo imaginar que cambia por completo el paisaje. Este año bien podría ser diferente de cada uno de los 25 años anteriores. Pero podría no, también.
La vasta, vasta y amplia mayoría de código paralelo y concurrente que existe ahora, y en el futuro previsible, no está escrito en lenguajes funcionales. Si busca aprender sobre el paralelismo, explore todos los mecanismos disponibles en F #, Haskell, etc .; pero no te limites a eso, es todo lo que digo.
La programación funcional tiene estructuras de datos inmutables y ningún efecto secundario que sea intrínsecamente adecuado para la programación paralela.
Esa es una idea errónea común. El paralelismo se basa únicamente en el rendimiento y la pureza degrada el rendimiento. Así que la programación puramente funcional no es un buen punto de partida si su objetivo es obtener un rendimiento decente. En general, pureza significa más asignación y peor localidad. En particular, las estructuras de datos puramente funcionales reemplazan las matrices con árboles y eso implica muchas más asignaciones y coloca mucha más carga sobre el recolector de basura.
Por ejemplo, mida el rendimiento del elegante "quicksort" puramente funcional en Haskell . La última vez que lo comprobé, era miles de veces más lenta que la solución imperativa convencional en mi máquina.
Además, nadie ha logrado implementar una estructura de datos del diccionario eficiente (pura o impura) o una clase eficaz puramente funcional en Haskell y nadie ha descubierto cómo escribir una estructura de datos disjuntos persistentes asintóticamente eficiente disjunta y no hay forma conocida de ¡implemente otras estructuras de datos básicas como diccionarios débiles puramente funcionales!
Además, aunque teóricamente es posible escribir código impuro en Haskell, el GC está muy optimizado para el código puro a expensas de la realización de la mutación. Por ejemplo, la tabla hash de GHC sigue siendo 26 veces más lenta que la de .NET . Históricamente, el rendimiento de la mutación se consideró tan poco importante en Haskell que escribir un único puntero a una matriz fue una operación O ( n ) en GHC durante cinco años .
Investigo cómo explotar el cómputo multinúcleo en un lenguaje funcional y el código de producción objetivo para algunas aplicaciones numéricas.
La mejor manera que he encontrado es aprender a escribir programas paralelos decentes para multinúcleos en el estilo imperativo (estudiar Cilk , en particular) y luego factorizar el código utilizando funciones de primera clase y la eliminación de la llamada final en el estilo funcional impuro .
Esto significa caché inconsciente estructuras de datos y algoritmos. Nadie ha hecho esto en Haskell. De hecho, ninguna de las investigaciones publicadas paralelamente a Haskell hasta la fecha ha mencionado siquiera el concepto esencial de la complejidad del caché . Además, aunque es ampliamente conocido que la evaluación no estricta (también llamada vaga) hace que el consumo de espacio sea impredecible, aún no se aprecia ampliamente que este mismo problema haga que la escalabilidad sea impredecible en múltiples núcleos.
F # tiene a Microsoft detrás, y sus construcciones paralelas como PLINQ, TPL, Async Workflow han sido bien documentadas y han mostrado algunos potenciales.
Están mucho más allá de mostrar potencial. Miles de aplicaciones comerciales se basan en esas fundaciones de fuerza industrial.
Sin embargo, la investigación sobre el paralelismo en Haskell es muy activa en este momento, y posee muchas características interesantes que aún no han sido respaldadas por F #:
¿Por qué asumes que son "buenas características"?
Sugiero leer el último artículo de Simon Marlow sobre esto:
"... una combinación de experiencia práctica e investigación nos ha llevado a concluir que este enfoque no está exento de inconvenientes. En pocas palabras, el problema es este: lograr el paralelismo con par
requiere que el programador comprenda las propiedades operacionales del lenguaje que están en mejor definido para la implementación (y en el peor de los casos indefinido). Esto hace que sea difícil de usar, y abundan las trampas: los nuevos usuarios tienen una alta tasa de fallas ... "
Mi pregunta es, ¿qué idioma debería elegir para el paralelismo funcional?
Aconsejo contra el código paralelo puramente funcional para la producción porque es un comodín completo. Suponiendo que esté feliz de sacrificar algo de pureza para obtener un rendimiento competitivo, uso y recomiendo F #.
No hay una respuesta objetiva. Para Haskell, hay un gran cuerpo de trabajo activo y ningún enfoque de "talla única". En cambio, en Haskell, se proporcionan muchas herramientas diferentes para lograr el paralelismo. ¿Cuál es el estado de la programación multinúcleo en Haskell?
Si el tipo de código que tiene en mente asigna mucha memoria, entonces puede encontrar que el recolector de basura GHC se escala mejor que el recolector de basura .NET. Hay alguna evidencia indirecta de que el .NET GC se convierte en un cuello de botella cuando varios hilos se están asignando mucho, y esto también es una espina en el costado de la mayoría de los coleccionistas de Java. Por otro lado, hemos prestado bastante atención al logro de una buena ubicación y escalabilidad en el recolector de basura GHC, principalmente porque no tenemos otra opción, la mayoría del código idiomático de Haskell se asigna de todos modos. Tengo puntos de referencia que se asignan como locos y siguen escalando más allá de 24 núcleos.
En Haskell, tenga en cuenta que obtiene una garantía de determinismo del sistema de tipos, que no obtiene en F #.
Usted mencionó Data Parallel Haskell: una nota de advertencia aquí, no está listo para su uso de producción en este momento, aunque el equipo de DPH espera que la próxima versión de GHC 7.2.1 tenga una implementación estable de DPH.