2010-10-02 16 views
204

Creo que la comunidad Erlang no es envidioso de Node.js como lo hace sin bloqueo de E/S de forma nativa y tiene formas de ampliar los despliegues fácilmente a más de un procesador (algo que ni siquiera incorporada en Node.js). Más detalles en http://journal.dedasys.com/2010/04/29/erlang-vs-node-js y Node.js or Erlang¿Cuál es la respuesta de Haskell a Node.js?

¿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 tener que recurrir a la programación de múltiples hilos?


Hay muchas cosas que son atractivas con Node.js

  1. Eventos: Ninguna manipulación hilo, el programador sólo proporciona devoluciones de llamada (como en el marco de Snap)
  2. devoluciones de llamada están garantizados para ser ejecutado en un solo hilo: no es posible una condición de carrera.
  3. Agradable y simple API UNIX-friendly. Bonificación: excelente soporte HTTP. DNS también disponible.
  4. Cada E/S es por defecto asíncrona. Esto hace que sea más fácil evitar bloqueos. Sin embargo, demasiado procesamiento de la CPU en una devolución de llamada afectará a otras conexiones (en este caso, la tarea debe dividirse en subtareas más pequeñas y reprogramarse).
  5. El mismo lenguaje para el lado del cliente y el lado del servidor. (No veo demasiado valor en esto, sin embargo, jQuery y Node.js comparten el modelo de programación de eventos, pero el resto es muy diferente. Simplemente no puedo ver cómo podría compartir código entre el lado del servidor y el lado del cliente ser útil en la práctica.)
  6. Todo esto empaquetado en un solo producto.
+16

Creo que debería hacer esta pregunta en [Programadores] (http://programmers.stackexchange.com/) en su lugar. – Jonas

+43

No incluir un fragmento de código no lo convierte en una pregunta subjetiva. – gawi

+1

Cierto, pero los programadores no son solo un sitio para preguntas subjetivas. Es un lugar para preguntas que no están directamente relacionadas con el código, p. elección de idioma Buena pregunta sin embargo. +1 – Jonas

Respuesta

212

Bien, así que habiendo observado un poco del node.js presentation al que @gawi me apuntó, puedo decir un poco más acerca de 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 considera que la falta de abstracción de un 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 obtener y más sólido. En particular:

  • usando un hilo por conexión le permite escribir código que expresa la comunicación con un único cliente, en lugar de que la escritura de código que se ocupa de todo los clientes al mismo tiempo. Piénselo de esta manera: un servidor que maneja múltiples clientes con hilos se ve casi igual a uno que maneja un solo cliente; la principal diferencia es que hay un fork en algún lugar del primero. Si el protocolo que está implementando es complejo, administrar la máquina de estado para múltiples clientes simultáneamente es bastante complicado, mientras que los subprocesos le permiten programar 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 son multitareas cooperativas, en lugar de multitareas preventivas, que es lo que obtienes con los subprocesos. La principal desventaja de la multitarea cooperativa es que el programador es responsable de asegurarse de que no haya inanición. Pierde modularidad: comete un error en un lugar y puede arruinar todo el sistema. Esto es realmente algo de lo que no querrás preocuparte, y la prevención es la solución simple. Además, la comunicación entre devoluciones de llamada no es posible (bloquearía).

  • la concurrencia no es difícil en Haskell, porque la mayoría del código es puro y por lo tanto es seguro para la ejecución de subprocesos. Hay primitivas de comunicación simple. Es mucho más difícil dispararse en el pie con concurrencia en Haskell que en un idioma con efectos secundarios sin restricciones.

+41

Ok, entonces entiendo que node.js es la solución a 2 problemas: 1- la concurrencia es difícil en la mayoría de los lenguajes , 2- usar hilos del sistema operativo es expansivo. Nodo.La solución js consiste en utilizar la concurrencia basada en eventos (w/libev) para evitar la comunicación entre subprocesos y evitar problemas de escalabilidad de los subprocesos del sistema operativo. Haskell no tiene el problema # 1 debido a la pureza. Para el n. ° 2, Haskell tiene hilos livianos + gestor de eventos que fue optimizado recientemente en GHC para contextos de gran escala. Además, el uso de Javascript no puede ser percibido como un plus para cualquier desarrollador de Haskell. Para algunas personas que usan el Marco Snap, Node.js es "simplemente malo". – gawi

+4

El procesamiento de solicitudes es la mayoría de las veces una secuencia de operaciones interdependientes. Tiendo a aceptar que usar devoluciones de llamada para cada operación de bloqueo puede ser engorroso. Los subprocesos son más adecuados que la devolución de llamada para esto. – gawi

+10

¡Sip! Y la nueva multiplexación de E/S en GHC 7 hace que escribir servidores en Haskell sea aún mejor. – andreypopp

153

Puede Haskell proporcionar algunos de los beneficios de Node.js, a saber, una solución limpia para evitar el bloqueo de E/S sin tener recurrir a la programación multi-hilo?

Sí, de hecho los eventos y los hilos se unifican en Haskell.

  • Puede programar en subprocesos ligeros explícitos (por ejemplo, millones de subprocesos en una sola computadora portátil).
  • O; puede programar en un estilo basado en eventos asíncronos, basado en notificaciones de eventos escalables.

Los hilos son en realidad implemented in terms of events, y se ejecutan en varios núcleos, con migración de hilos sin costura, con rendimiento documentado y aplicaciones.

E.g. para

colecciones concurrentes Nbody en 32 núcleos

alt text

En Haskell tiene ambos eventos e hilos, y como es todos los eventos bajo el capó.

Read the paper describiendo la implementación.

+2

Gracias. Necesito digerir todo esto ... Esto parece ser específico de GHC. Supongo que está bien. El lenguaje Haskell es alguna vez como cualquier cosa que GHC pueda compilar. De manera similar, la "plataforma" Haskell es más o menos el tiempo de ejecución de GHC. – gawi

+1

@gawi: Eso y todos los otros paquetes que se incluyen directamente en él para que sea útil nada más sacarlo de la caja. Y esta es la misma imagen que vi en mi curso de CS; y la mejor parte es que no es difícil en Haskell lograr resultados asombrosos similares en sus propios programas. –

+1

Hola Don, ¿crees que podrías vincular al servidor web haskell que tiene el mejor rendimiento (Warp) cuando respondes preguntas como estas? Aquí está el punto de referencia bastante relevante contra Node.js: http://www.yesodweb.com/blog/2011/03/preliminary-warp-cross-language-benchmarks –

18

En primer lugar, no considero que node.js esté haciendo lo correcto al exponer 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.

Eventos: Ninguna manipulación de hilo, el programador sólo se ofrece devoluciones de llamada (como en el marco de Snap)

Así que con esto en mente, se puede escribir usando un estilo asíncrona si así lo desea, pero al hacerlo por lo que se perderá la oportunidad de escribir en un estilo síncrono eficiente, con un hilo por solicitud. Haskell es ridículamente eficiente en el código sincrónico, especialmente cuando se compara con otros lenguajes. Son todos los eventos debajo.

Las devoluciones de llamadas están garantizadas para ejecutarse en un solo hilo: no es posible una condición de carrera.

Aún puede haber una condición de carrera en node.js, pero es más difícil.

Todas las solicitudes están en su propio hilo. Cuando escribe código que tiene que comunicarse con otros hilos, es muy simple hacerlo seguro gracias a las primitivas de concurrencia de Haskell.

API sencilla y fácil de UNIX. Bonificación: excelente soporte HTTP. DNS también disponible.

Eche un vistazo al hackage y compruébalo usted mismo.

Cada E/S es por defecto asíncrona (aunque a veces puede ser molesto). Esto hace que sea más fácil evitar bloqueos. Sin embargo, demasiado procesamiento de la CPU en una devolución de llamada afectará a otras conexiones (en este caso, la tarea debe dividirse en subtareas más pequeñas y reprogramarse).

No tiene tales problemas, ghc distribuirá su trabajo entre los hilos del sistema operativo real.

El mismo lenguaje para el lado del cliente y del lado del servidor. (No veo demasiado valor en esto, sin embargo, JQuery y Node.js comparten el modelo de programación de eventos, pero el resto es muy diferente. Simplemente no puedo ver cómo podría compartir el código entre el lado del servidor y el lado del cliente ser útil en la práctica.)

Haskell no puede ganar aquí ... ¿verdad? Piénselo de nuevo, http://www.haskell.org/haskellwiki/Haskell_in_web_browser.

Todo esto empaquetado en un solo producto.

Descargar ghc, fire up cabal. Hay un paquete para cada necesidad.

+0

Estaba jugando al abogado del diablo. Entonces, sí, estoy de acuerdo con tus puntos. Excepto la unificación del lenguaje del lado del cliente y del lado del servidor. Si bien creo que es técnicamente factible, no creo que eventualmente pueda reemplazar todo el ecosistema Javascript en su lugar hoy (JQuery y amigos). Si bien es un argumento presentado por los seguidores de Node.js, no creo que sea muy importante. ¿De verdad necesitas compartir tanto código entre tu capa de presentación y tu back-end? ¿Realmente pretendemos que los programadores conozcan un solo idioma? – gawi

+0

La verdadera victoria es que puede representar páginas tanto del lado del servidor como del lado del cliente, facilitando la creación de páginas en tiempo real. –

+0

@dan_waterworth exactamente, vea [meteor] (http://meteor.com) o [derby.js] (http://derbyjs.com) – mb21

5

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. Aquí está la referencia contra el nodo: http://www.yesodweb.com/blog/2011/03/preliminary-warp-cross-language-benchmarks

Proporcione 4 núcleos Haskell y puede hacer 100k (simples) solicitudes por segundo en una sola aplicación. Nodo no puede hacer tantas, y no puede escalar una sola aplicación entre núcleos. Y no tiene que hacer nada para obtener esto porque el tiempo de ejecución de Haskell no es bloqueante. El único otro lenguaje (relativamente común) que tiene IO sin bloqueo incorporado en el tiempo de ejecución es Erlang.

+14

¿Ridículo? La pregunta no es "¿tiene Haskell una respuesta?" Sino "¿cuál es la respuesta de Haskell?". En el momento en que se formuló la pregunta, GHC 7 ni siquiera se lanzó, por lo que Haskell aún no estaba "en el juego" (excepto tal vez para los frameworks que usan libev como Snap). Aparte de eso, estoy de acuerdo. – gawi

+1

No sé si esto fue cierto cuando publicó esta respuesta, pero ahora, de hecho, hay módulos de nodo que permiten que las aplicaciones de nodo escalen fácilmente entre núcleos. Además, ese enlace está comparando node.js ejecutándose en un solo núcleo con Haskell ejecutándose en 4 núcleos. Me gustaría ver que se ejecute nuevamente en una configuración más justa, pero desafortunadamente el repositorio github ya no está. –

+2

Haskell utilizando más de 4 núcleos degrada el rendimiento de la aplicación. Hubo un documento sobre este tema, en el que se trabajó activamente, pero sigue siendo un problema. Por lo tanto, ejecutar 16 instancias de Node.js en el servidor de 16 núcleos probablemente será mucho mejor que una sola aplicación de ghc que use + RTS -N16, que de hecho será más lenta que + RTS -N1 debido a este error de tiempo de ejecución. Es porque usan solo un IOManager que se ralentizará cuando se utilicen con muchos hilos del sistema operativo. Espero que solucionen este error, pero existe desde entonces, así que no me gustaría tener muchas esperanzas ... – Kr0e

5

Los eventos en mi humilde opinión son buenos, pero la programación mediante 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 los hace escalables y flexibles. La más importante, la naturaleza sin estado de HTTP. Esto mejora la navegabilidad, pero esto impone una inversión de control donde el elemento IO (el servidor web en este caso) llama a diferentes manejadores en el código de la aplicación. Este modelo de evento -o modelo de devolución de llamada, más exactamente dicho- es una pesadilla, ya que las devoluciones de llamada no comparten ámbitos variables, y se pierde una visión intuitiva de la navegación. Es muy difícil evitar todos los posibles cambios de estado cuando el usuario navega hacia adelante y hacia atrás, entre otros problemas.

Se puede decir que los problemas son similares a la programación de la GUI donde el modelo de evento funciona bien, pero las GUI no tienen navegación ni 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 de magia omnipresentes sin cuestionar la raíz del problema: el modelo de devolución de llamada y su inherente falta de compartición de ámbitos variables, y sin secuenciación, por lo que la secuencia tiene que construirse mediante identificadores de enlace.

Existen marcos basados ​​en secuencia como ocsigen (ocaml) seaside (smalltalk) WASH (descontinuado, Haskell) y mflow (Haskell) que resuelven el problema de la gestión estatal mientras mantienen la navegabilidad y REST-plenitud. Dentro de estos marcos, el programador puede expresar la navegación como una secuencia imperativa en la que el programa envía páginas y espera respuestas en un solo hilo, las variables están en el alcance y el botón Atrás funciona automáticamente. Esto produce inherentemente 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)

+0

En node.js las devoluciones de llamada se usan para manejar E/S asíncronas, p. a las bases de datos.Estás hablando de algo diferente que, aunque es interesante, no responde la pregunta. –

+0

Tienes razón. Me tomó tres años tener una respuesta que, espero, satisfaga sus objeciones: https://github.com/transient-haskell – agocorona

+0

Nodo ahora admite funciones asincrónicas, lo que significa que puede escribir un código de estilo imperativo que sea realmente asincrónico. Utiliza promesas bajo el capó. –

8

Personalmente, veo Node.js y la programación con devoluciones de llamadas es innecesariamente de bajo nivel y algo poco natural. ¿Por qué programar con devoluciones de llamadas cuando un buen tiempo de ejecución como el que se encuentra en GHC puede manejar las devoluciones de llamadas y hacerlo de manera bastante eficiente?

Mientras tanto, el tiempo de ejecución de GHC ha mejorado mucho: ahora presenta un "nuevo administrador nuevo de IO" llamado MIO donde "M" significa multicore, creo. Se basa en la base del administrador de IO existente y su objetivo principal es superar la causa de la degradación del rendimiento de 4+ núcleos. Las cifras de rendimiento proporcionadas en este documento son bastante impresionantes. Véalo a usted mismo:

Con Mio, servidores HTTP realistas en escala Haskell de 20 núcleos de CPU, logrando un rendimiento máximo hasta factor de 6.5x en comparación con los mismos servidores que utilizan versiones anteriores de GHC. La latencia de los servidores Haskell también se ha mejorado: [...] bajo una carga moderada, reduce el tiempo de respuesta esperada por 5.7 veces en comparación con las versiones anteriores de GHC

Y:

También mostramos que con Mio, McNettle (un controlador SDN escrito en Haskell) puede escalar eficazmente a más de 40 núcleos, alcanzar un rendimiento de más de 20 millones de solicitudes nuevas por segundo en una sola máquina y convertirse así en el más rápido de todos los controladores SDN existentes.

Mio ha logrado la versión GHC 7.8.1. Personalmente, veo esto como un importante 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.

2
+1

¿Cómo responde esto la pregunta? – dfeuer

+1

@dfeuer El enlace debe leer como, Snap Haskell Web Framework ha dejado de libev, no sé por qué el formato está fallando. El tiempo de ejecución del servidor de nodos era sobre Linux libev cuando comenzó, y también lo fue Snap Web FrameWork. Haskell con Snap es como ECMAscript con nodejs, por lo que la forma en que Snap evoluciona junto con nodejs es más relevante que Haskell, que puede compararse más correctamente con ECMAscript en este contexto. –

+0

@Robin Green Gracias. :) –

Cuestiones relacionadas