web-dev-qa-db-fra.com

Quelle est la réponse de Haskell à Node.js?

Je pense que la communauté Erlang n’envie pas Node.js, car elle fait nativement des E/S non-bloquantes et elle dispose de moyens pour faire évoluer facilement les déploiements vers plusieurs processeurs (quelque chose qui n’est même pas intégré à Node.js). Plus de détails sur http://journal.dedasys.com/2010/04/29/erlang-vs-node-js et Node.js ou Erlang

Qu'en est-il de Haskell? Haskell peut-il fournir certains des avantages de Node.js, à savoir une solution propre pour éviter le blocage des E/S sans recourir à la programmation multi-thread?


Il y a beaucoup de choses qui attirent avec Node.js

  1. Evénements: pas de manipulation de thread, le programmeur ne fournit que des rappels (comme dans le framework Snap)
  2. Les rappels sont garantis pour être exécutés dans un seul thread: aucune condition de concurrence critique n'est possible.
  3. API simple et agréable pour UNIX. Bonus: Excellent support HTTP. DNS également disponible.
  4. Chaque E/S est par défaut asynchrone. Cela rend plus facile d'éviter les verrous. Cependant, un traitement excessif de la CPU dans un rappel aura un impact sur les autres connexions (dans ce cas, la tâche doit être scindée en sous-tâches plus petites et réorganisée).
  5. Même langue pour le côté client et le côté serveur. Cependant, jQuery et Node.js partagent le modèle de programmation d'événements, mais le reste est très différent. Je ne vois pas comment le partage de code entre le côté serveur et le côté client pourrait être utile dans la pratique.)
  6. Tout cela emballé dans un seul produit.
214
gawi

Ok, donc après avoir regardé un peu le présentation de node.js que @gawi m'a indiqué, je peux en dire un peu plus sur la façon dont Haskell se compare à node.js. Dans la présentation, Ryan décrit certains des avantages de Green Threads, mais ajoute ensuite qu'il ne considère pas le manque d'abstraction de fil comme un désavantage. Je ne suis pas d'accord avec sa position, en particulier dans le contexte de Haskell: je pense que les abstractions fournies par les threads sont essentielles pour rendre le code serveur plus facile à obtenir et plus robuste. En particulier:

  • utiliser un thread par connexion vous permet d'écrire du code qui exprime la communication avec un seul client, plutôt que d'écrire du code qui traite tous les clients en même temps . Pensez-y comme ceci: un serveur qui gère plusieurs clients avec des threads a presque la même apparence que celui qui gère un seul client; la principale différence est qu'il y a un fork quelque part dans l'ancien. Si le protocole que vous implémentez est complexe, la gestion de la machine à états pour plusieurs clients en même temps devient assez délicate, alors que les threads vous permettent simplement de créer un script de communication avec un seul client. Le code est plus facile à comprendre et à comprendre et à gérer.

  • les rappels sur un seul thread de système d’exploitation constituent un mode multitâche coopératif, par opposition au mode multitâche préemptif, qui correspond à ce que vous obtenez avec les threads. Le principal inconvénient du multitâche coopératif est qu’il incombe au programmeur de s’assurer qu’il n’ya pas de famine. Il perd la modularité: faites une erreur à un endroit et cela peut tout bousiller. C'est vraiment quelque chose dont vous ne voulez pas vous inquiéter, et la préemption est la solution simple. De plus, la communication entre les rappels n'est pas possible (cela entraînerait un blocage).

  • la concurrence d'accès n'est pas difficile en Haskell, car la plupart du code est pur et donc thread-safe par construction. Il existe des primitives de communication simples. Il est beaucoup plus difficile de se tirer une balle dans le pied avec concurrence dans Haskell que dans une langue aux effets secondaires illimités.

218
Simon Marlow

Haskell peut-il fournir certains des avantages de Node.js, à savoir une solution propre pour éviter le blocage des E/S sans recourir à la programmation multi-thread?

Oui, en fait, les événements et les discussions sont unifiés dans Haskell.

  • Vous pouvez programmer des threads légers explicites (par exemple, des millions de threads sur un seul ordinateur portable).
  • Ou; vous pouvez programmer dans un style dépendant d'événements asynchrones, basé sur une notification d'événement évolutive.

Les threads sont en réalité implémentés en termes d'événements et s'exécutent sur plusieurs cœurs, avec une migration de thread transparente, avec des performances documentées et des applications.

Par exemple. pour

Collections simultanées nbody sur 32 cœurs

alt text

Dans Haskell, vous avez à la fois des événements et des discussions, et comme il s’agit de tous les événements qui se déroulent sous le capot.

Lire le papier décrivant la mise en oeuvre.

154
Don Stewart

Premièrement, je ne pense pas que node.js fasse ce qu'il convient de faire en exposant tous ces rappels. Vous finissez par écrire votre programme en CPS (style de passage continu) et je pense que le compilateur devrait être chargé de cette transformation.

Evénements: pas de manipulation de thread, le programmeur ne fournit que des rappels (comme dans le framework Snap)

En gardant cela à l’esprit, vous pouvez écrire en utilisant un style asynchrone si vous le souhaitez, mais vous perdriez ainsi l’écriture dans un style synchrone efficace, avec un thread par requête. Haskell est ridiculement efficace en code synchrone, en particulier par rapport aux autres langues. Ce sont tous les événements en dessous.

Les rappels sont garantis pour être exécutés dans un seul thread: aucune condition de concurrence critique n'est possible.

Vous pouvez toujours avoir une condition de concurrence critique dans node.js, mais c'est plus difficile.

Chaque demande est dans son propre fil. Lorsque vous écrivez du code devant communiquer avec d'autres threads, il est très simple de le rendre threadsafe grâce aux primitives de simultanéité de haskell.

API simple et agréable pour UNIX. Bonus: Excellent support HTTP. DNS également disponible.

Jetez un coup d'oeil au hackage et voyez par vous-même.

Chaque E/S est par défaut asynchrone (cela peut parfois être gênant). Cela rend plus facile d'éviter les verrous. Cependant, un traitement excessif de la CPU dans un rappel aura un impact sur les autres connexions (dans ce cas, la tâche doit être scindée en sous-tâches plus petites et réorganisée).

Vous n’avez pas de tels problèmes, ghc répartira votre travail entre de vrais threads de système d’exploitation.

Même langue pour le côté client et le côté serveur. (Je ne vois pas trop de valeur dans celui-ci, cependant. JQuery et Node.js partagent le modèle de programmation d'événements, mais le reste est très différent. Je ne vois tout simplement pas comment le partage de code entre côté serveur et côté client pourrait être utile dans la pratique.)

Haskell ne peut probablement pas gagner ici ... non? Pensez-y de nouveau, http://www.haskell.org/haskellwiki/Haskell_in_web_browser .

Tout cela emballé dans un seul produit.

Téléchargez ghc, lancez la cabale. Il y a un paquet pour chaque besoin.

18
dan_waterworth

Personnellement, je considère Node.js et la programmation avec des rappels comme une chose inutilement basse et un peu artificielle. Pourquoi programmer avec des callbacks quand une bonne exécution telle que celle trouvée dans GHC peut gérer les callbacks pour vous et le faire assez efficacement?

Dans l’intervalle, le temps d’exécution de GHC s’est considérablement amélioré: il comporte désormais un "nouveau nouveau IO manager" "appelé" MIO où " M "signifie multicore je crois. Il s’appuie sur la base du gestionnaire IO) existant et son objectif principal est de remédier à la dégradation des performances à partir de 4 cœurs. Les performances présentées ici sont impressionnantes. Voyez vous-même:

Avec Mio, les serveurs HTTP réalistes de Haskell peuvent gérer jusqu'à 20 cœurs de processeur, avec des performances maximales de 6,5 fois supérieures à celles des mêmes serveurs utilisant les versions précédentes de GHC. La latence des serveurs Haskell a également été améliorée: [...] sous une charge modérée, réduit le temps de réponse attendu de 5,7 fois par rapport aux versions précédentes de GHC.

Et:

Nous montrons également qu’avec Mio, McNettle (un contrôleur SDN écrit en Haskell) peut s’adapter efficacement à plus de 40 cœurs, atteindre plus de 20 millions de nouvelles requêtes par seconde sur une seule machine et devenir ainsi le plus rapide de tous les contrôleurs SDN existants. .

Mio a été intégré à la version 7.8.1 de GHC. Personnellement, je considère cela comme une avancée majeure dans les performances de Haskell. Il serait très intéressant de comparer les performances des applications Web existantes compilées avec la version précédente de GHC et avec la version 7.8.1.

8
vlprans

La question est assez ridicule parce que 1) Haskell a déjà résolu ce problème de manière bien meilleure et 2) à peu près de la même manière que Erlang. Voici le point de repère contre le noeud: http://www.yesodweb.com/blog/2011/03/preliminary-warp-cross-language-benchmarks

Donnez à Haskell 4 cœurs et il peut faire 100 000 (simples) demandes par seconde dans une seule application. Node ne peut pas en faire autant, et ne peut pas redimensionner une seule application sur plusieurs cœurs. Et vous n'avez rien à faire pour récupérer cela, car l'exécution de Haskell n'est pas bloquante. Erlang est le seul langage (relativement commun) non bloquant IO intégré au moteur d’exécution).

5
Greg Weber

Les événements IMHO sont bons, mais la programmation par rappels ne l’est pas.

La plupart des problèmes qui rendent spécial le codage et le débogage des applications Web proviennent de ce qui les rend évolutifs et flexibles. Le plus important, la nature sans état de HTTP. Cela améliore la navigabilité, mais cela impose une inversion de contrôle dans laquelle l'élément IO (le serveur Web dans ce cas) appelle différents gestionnaires dans le code de l'application. Ce modèle d'événement ou de rappel, plus précisément dit- est un cauchemar, car les rappels ne partagent pas des portées variables, et une vue intuitive de la navigation est perdue Il est très difficile d'empêcher tous les changements d'état possibles lorsque l'utilisateur navigue, entre autres problèmes.

On peut dire que les problèmes sont similaires à la programmation d'interface graphique dans laquelle le modèle d'événement fonctionne correctement, mais les interfaces graphiques n'ont pas de bouton de navigation ni de retour. Cela multiplie les transitions d'état possibles dans les applications Web. Le résultat de la tentative de résolution de ce problème est la lourdeur des frameworks avec des configurations compliquées, de nombreux identifiants magiques omniprésents sans remettre en cause la racine du problème: le modèle de rappel et son manque inhérent de partage des étendues variables, et pas de séquençage, la séquence doit donc être construit en liant des identifiants.

Il existe des frameworks séquentiels tels que ocsigen (ocaml) seaside (Smalltalk) WASH (discontinued, Haskell) et mflow (Haskell) qui résolvent le problème de la gestion de l'état tout en maintenant la navigabilité et la fiabilité REST. dans ces cadres, le programmeur peut exprimer la navigation comme une séquence impérative dans laquelle le programme envoie des pages et attend les réponses dans un seul fil, les variables sont dans la portée et le bouton Précédent fonctionne automatiquement. Cela produit intrinsèquement un code plus court, plus sûr et plus lisible dans lequel la navigation est clairement visible pour le programmeur. (bon avertissement: je suis le développeur de mflow)

5
agocorona
1
Chawathe Vipul