Creo que la comunidad de Erlang no tiene envidia de Node.js, ya que lo hace sin bloqueo de E / S de forma nativa y tiene formas de escalar fácilmente las implementaciones a más de un procesador (algo que ni siquiera está integrado en Node.js). Más detalles en http://journal.dedasys.com/2010/04/29/erlang-vs-node-js y Node.js o Erlang
¿Qué hay de Haskell? ¿Puede Haskell proporcionar algunos de los beneficios de Node.js, es decir, una solución limpia para evitar el bloqueo de E / S sin recurrir a la programación de subprocesos múltiples?
Hay muchas cosas que son atractivas con Node.js
- Eventos: sin manipulación de subprocesos, el programador solo proporciona devoluciones de llamada (como en el marco Snap)
- Se garantiza que las devoluciones de llamada se ejecuten en un solo hilo: no es posible la condición de carrera.
- Agradable y simple API compatible con UNIX. Bonificación: Excelente soporte HTTP. DNS también disponible.
- Cada E / S es por defecto asíncrona. Esto hace que sea más fácil evitar las cerraduras. Sin embargo, el procesamiento excesivo de la CPU en una devolución de llamada afectará a otras conexiones (en este caso, la tarea debería dividirse en subtareas más pequeñas y reprogramarse).
- Mismo idioma para el lado del cliente y del lado del servidor. (Sin embargo, no veo demasiado valor en este caso. JQuery y Node.js comparten el modelo de programación de eventos, pero el resto es muy diferente. Simplemente no puedo ver cómo compartir código entre el lado del servidor y el lado del cliente Ser útil en la práctica.)
- Todo esto empaquetado en un solo producto.
Respuestas:
De acuerdo, después de haber visto un poco de la presentación de node.js a la que @gawi me señaló, puedo decir un poco más sobre cómo Haskell se compara con node.js. En la presentación, Ryan describe algunos de los beneficios de Green Threads, pero luego continúa diciendo que no encuentra que la falta de abstracción de hilo sea una desventaja. No estoy de acuerdo con su posición, particularmente en el contexto de Haskell: creo que las abstracciones que proporcionan los hilos son esenciales para hacer que el código del servidor sea más fácil de corregir y más robusto. En particular:
El uso de un subproceso por conexión le permite escribir código que expresa la comunicación con un solo cliente, en lugar de escribir código que trata con todos los clientes al mismo tiempo. Piénselo de esta manera: un servidor que maneja múltiples clientes con hilos se ve casi igual que uno que maneja un solo cliente; La principal diferencia es que hay un
fork
lugar en el primero. Si el protocolo que está implementando es del todo complejo, administrar la máquina de estado para varios clientes simultáneamente es bastante complicado, mientras que los hilos le permiten simplemente escribir la comunicación con un solo cliente. El código es más fácil de entender y más fácil de entender y mantener.las devoluciones de llamada en un solo subproceso del sistema operativo es multitarea cooperativa, a diferencia de la multitarea preventiva, que es lo que obtienes con los subprocesos. La principal desventaja con la multitarea cooperativa es que el programador es responsable de asegurarse de que no haya inanición. Pierde modularidad: comete un error en un solo lugar y puede arruinar todo el sistema. Esto es realmente algo de lo que no debe preocuparse, y la prevención es la solución simple. Además, la comunicación entre devoluciones de llamada no es posible (sería un punto muerto).
la concurrencia no es difícil en Haskell, porque la mayoría del código es puro y, por lo tanto, es seguro para subprocesos por construcción. Hay simples primitivas de comunicación. Es mucho más difícil dispararse en el pie con concurrencia en Haskell que en un idioma con efectos secundarios sin restricciones.
fuente
Sí, de hecho, los eventos y los hilos están unificados en Haskell.
Los hilos se implementan realmente en términos de eventos y se ejecutan en múltiples núcleos, con migración de subprocesos sin interrupciones, con rendimiento documentado y aplicaciones.
Por ejemplo para
Colecciones concurrentes nbody en 32 núcleos
En Haskell tienes tanto eventos como hilos, y como todos los eventos están bajo el capó.
Lea el documento que describe la implementación.
fuente
En primer lugar, no creo que node.js esté haciendo lo correcto exponiendo todas esas devoluciones de llamada. Terminas escribiendo tu programa en CPS (estilo de paso de continuación) y creo que debería ser el trabajo del compilador hacer esa transformación.
Con esto en mente, puede escribir usando un estilo asíncrono si lo desea, pero al hacerlo, se perdería la escritura en un estilo sincrónico eficiente, con un hilo por solicitud. Haskell es ridículamente eficiente en el código síncrono, especialmente en comparación con otros idiomas. Son todos los eventos debajo.
Aún podría tener una condición de carrera en node.js, pero es más difícil.
Cada solicitud está en su propio hilo. Cuando escribes código que tiene que comunicarse con otros hilos, es muy sencillo hacerlo seguro gracias a las primitivas de concurrencia de Haskell.
Echa un vistazo a los ataques y compruébalo por ti mismo.
No tiene tales problemas, ghc distribuirá su trabajo entre los hilos reales del sistema operativo.
Haskell no puede ganar aquí ... ¿verdad? Piense de nuevo, http://www.haskell.org/haskellwiki/Haskell_in_web_browser .
Descarga ghc, enciende cabal. Hay un paquete para cada necesidad.
fuente
Personalmente, veo Node.js y la programación con devoluciones de llamada como algo innecesariamente de bajo nivel y un poco antinatural. ¿Por qué programar con devoluciones de llamada cuando un buen tiempo de ejecución como el que se encuentra en GHC puede manejar las devoluciones de llamada por usted y hacerlo de manera bastante eficiente?
Mientras tanto, el tiempo de ejecución de GHC ha mejorado enormemente: ahora presenta un "nuevo nuevo administrador de E / S" llamado MIO donde "M" significa multinúcleo, creo. Se basa en la base del administrador de E / S existente y su objetivo principal es superar la causa de la degradación del rendimiento de más de 4 núcleos. Los números de rendimiento proporcionados en este documento son bastante impresionantes. Verse a sí mismo:
Y:
Mio ha llegado a la versión GHC 7.8.1. Personalmente, veo esto como un gran paso adelante en el rendimiento de Haskell. Sería muy interesante comparar el rendimiento de las aplicaciones web existentes compilado por la versión anterior de GHC y 7.8.1.
fuente
Los eventos de mi humilde opinión son buenos, pero la programación por medio de devoluciones de llamada no lo es.
La mayoría de los problemas que hacen especial la codificación y depuración de aplicaciones web proviene de lo que las hace escalables y flexibles. Lo más importante, la naturaleza sin estado de HTTP. Esto mejora la navegabilidad, pero impone una inversión de control donde el elemento IO (el servidor web en este caso) llama a diferentes controladores en el código de la aplicación. Este modelo de evento -o modelo de devolución de llamada, dicho con mayor precisión- es una pesadilla, ya que las devoluciones de llamada no comparten ámbitos variables y se pierde una vista intuitiva de la navegación. Es muy difícil evitar todos los posibles cambios de estado cuando el usuario navega de un lado a otro, entre otros problemas.
Se puede decir que los problemas son similares a la programación de GUI donde el modelo de evento funciona bien, pero las GUI no tienen navegación ni botón de retroceso. Eso multiplica las transiciones de estado posibles en las aplicaciones web. El resultado del intento de resolver este problema son marcos pesados con configuraciones complicadas y muchos identificadores mágicos omnipresentes sin cuestionar la raíz del problema: el modelo de devolución de llamada y su falta inherente de compartir ámbitos variables, y ninguna secuencia, por lo que la secuencia tiene que ser construido vinculando identificadores.
Existen marcos basados en secuencia como ocsigen (ocaml) seaside (smalltalk) WASH (descontinuado, Haskell) y mflow (Haskell) que resuelven el problema de la gestión del estado mientras mantienen la navegabilidad y la REST-plenitud. Dentro de estos marcos, el programador puede expresar la navegación como una secuencia imperativa donde el programa envía páginas y espera respuestas en un solo hilo, las variables están dentro del alcance y el botón Atrás funciona automáticamente. Esto inherentemente produce un código más corto, más seguro y más legible donde la navegación es claramente visible para el programador. (advertencia justa: soy el desarrollador de mflow)
fuente
La pregunta es bastante ridícula porque 1) Haskell ya ha resuelto este problema de una manera mucho mejor y 2) más o menos de la misma manera que Erlang lo ha hecho. Aquí está el punto de referencia contra el nodo: http://www.yesodweb.com/blog/2011/03/preliminary-warp-cross-language-benchmarks
Dale a Haskell 4 núcleos y puede hacer 100k solicitudes (simples) por segundo en una sola aplicación. Node no puede hacer tantos, y no puede escalar una sola aplicación a través de los núcleos. Y no tiene que hacer nada para cosechar esto porque el tiempo de ejecución de Haskell no bloquea. El único otro lenguaje (relativamente común) que tiene IO sin bloqueo integrado en el tiempo de ejecución es Erlang.
fuente
pm2 -i max path/to/app.js
se escalará automáticamente al número óptimo de instancias en función de los núcleos disponibles. Además, Node también no se bloquea por defecto.Al igual que nodejs ha dejado de liberar, el Marco web Snap Haskell también ha dejado de liberar .
fuente