什么是Haskell对Node.js的响应?

我相信Erlang社区并不嫉妒Node.js,因为它原生地实现了非阻塞I / O,并且有方法可以轻松地将部署扩展到多个处理器(即使Node.js中没有内置的东西)。 http://journal.dedasys.com/2010/04/29/erlang-vs-node-js和Node.js或Erlang的更多细节

那Haskell呢? Haskell可以提供Node.js的一些好处,也就是一个干净的解决scheme,可以避免阻塞I / O而无需使用multithreading编程?


Node.js有很多很吸引人的地方

  1. 事件:没有线程操作,程序员只提供callback(如在Snap框架中)
  2. callback保证在一个线程中运行:没有竞争条件可能。
  3. 好的和简单的UNIX友好的API。 奖金:优秀的HTTP支持。 DNS也可用。
  4. 每个I / O默认是asynchronous的。 这使得更容易避免locking。 但是,callback中的CPU处理太多会影响其他连接(在这种情况下,任务应该拆分成更小的子任务并重新调度)。
  5. 客户端和服务器端的语言相同。 (但是我没有看到太多的价值,但是jQuery和Node.js共享事件编程模型,但是其他的却是截然不同的,我只是看不出服务器端和客户端之间的共享代码如何在实践中是有用的。)
  6. 所有这些包装在一个单一的产品。

好的,看过@gawi指出的node.js演示文稿 ,我可以多说一下Haskell与node.js的比较。 在演讲中,Ryan描述了Green Threads的一些好处,但是接着他说,他并不觉得缺乏线程抽象是一个缺点。 我不同意他的立场,尤其是在Haskell的背景下:我认为线程提供的抽象对于使服务器代码更容易正确和更健壮是必不可less的。 尤其是:

  • 每个连接使用一个线程可让您编写表示与单个客户端进行通信的代码,而不是编写同时处理所有客户端的代码。 可以这样想:用线程处理多个客户端的服务器几乎与处理单个客户端的服务器相同; 主要的区别是前者有一个fork 。 如果你正在实现的协议非常复杂,同时为多个客户端pipe理状态机变得非常棘手,而线程则让你只用一个客户端来编写通信脚本。 代码更容易理解,更易于理解和维护。

  • 在一个单一的操作系统线程callback是合作的多任务,而不是先发制人的多任务,这是你得到的线程。 合作多任务的主要缺点是程序员有责任确保没有饥饿。 它失去了模块性:在一个地方犯了一个错误,并且可能导致整个系统的崩溃。 这实在是你不想担心的事情,抢占是简单的解决scheme。 此外,callback之间的通信是不可能的(它会死锁)。

  • 在Haskell中并发性并不难,因为大多数代码是纯的,所以是通过构造来保证线程安全的。 有简单的通信原语。 在Haskell中并发处理自己而不是在不受限制的副作用的情况下,要更加困难。

Haskell可以提供Node.js的一些好处,也就是一个干净的解决scheme,可以避免阻塞I / O而无需使用multithreading编程?

是的,事实上,事件和线程在Haskell中是统一的。

  • 您可以使用明确的轻量级线程(例如,单台笔记本电脑上的数百万个线程)编程。
  • 要么; 您可以基于可伸缩事件通知以asynchronous事件驱动样式进行编程。

线程实际上是通过事件来实现的 ,可以跨多个内核运行,具有无缝线程迁移,logging的性能和应用程序。

例如

  • 大规模并发的作业编排
  • 并发集合可在32或48核上进行缩放
  • 工具支持分析和debuggingmultithreading/多事件程序 。
  • 高性能的事件驱动的Web服务器 。
  • 有趣的用户: 如高频交易 。

并发收集32个核心上的nbody

替代文字

在Haskell中你既有事件又有线程,因为它是引擎盖下的所有事件。

阅读描述实施的论文 。

首先,我不认为node.js正在做所有这些callback的正确的事情。 你最终用CPS编写你的程序(continuation passing style),我认为这应该是编译器的工作。

事件:没有线程操作,程序员只提供callback(如在Snap框架中)

因此,考虑到这一点,如果您愿意,可以使用asynchronous样式编写,但这样做会导致您错过了以高效的同步样式编写代码,每个请求只有一个线程。 Haskell在同步代码上效率很高,特别是与其他语言相比。 这是所有的事件。

callback保证在一个线程中运行:没有竞争条件可能。

在node.js中你仍然可以有一个竞争条件,但是更困难。

每个请求都在它自己的线程中。 当你编写与其他线程通信的代码时,由于haskell的并发原语使线程安全非常简单。

好的和简单的UNIX友好的API。 奖金:优秀的HTTP支持。 DNS也可用。

看看哈克,看看自己。

每个I / O默认是asynchronous的(尽pipe有时候这可能会令人讨厌)。 这使得更容易避免locking。 但是,callback中的CPU处理太多会影响其他连接(在这种情况下,任务应该拆分成更小的子任务并重新调度)。

你没有这样的问题,ghc将在真正的操作系统线程中分配你的工作。

客户端和服务器端的语言相同。 (但是我并没有看到太多的价值,但是JQuery和Node.js共享事件编程模型,但是其他的很不一样,我只是看不出服务器端和客户端之间的共享代码是如何实现的在实践中是有用的。)

哈斯克尔不可能赢在这里…对不对? 再想一想, http://www.haskell.org/haskellwiki/Haskell_in_web_browser

所有这些包装在一个单一的产品。

下载ghc,启动cabal。 有一个每个需要的包。

我个人认为Node.js和callback编程是不必要的低级和有点不自然的事情。 为什么使用callback进行编程时,如GHC中find一个良好的运行时可能会为您处理callback,并相当有效地执行callback?

与此同时,GHC的运行时间已经有了很大的提高:现在它有一个名为MIO的“新的IOpipe理器”,其中“M”代表多核心,我相信。 它build立在现有IOpipe理器的基础上,其主要目标是克服4核以上性能下降的原因。 本文提供的绩效数据相当令人印象深刻。 看看你自己:

借助Mio,Haskell中真实的HTTP服务器可扩展到20个CPU内核,与使用GHC以前版本的相同服务器相比,实现了高达6.5倍的峰值性能。 Haskell服务器的延迟也得到了改善:在中等负载下,与以前版本的GHC相比,预期响应时间减less了5.7倍

和:

我们还可以看出,使用Mio,McNettle(一种用Haskell编写的SDN控制器)可以有效扩展到40多个内核,在单台机器上每秒能够达到2000万个新请求,从而成为所有现有SDN控制器中最快的。

宇达电通已经将其转化为GHC 7.8.1版本。 我个人认为这是Haskell性能的一大进步。 比较以前GHC版本和7.8.1编译的现有web应用程序的性能将是非常有趣的。

这个问题相当荒谬,因为1)Haskell已经以更好的方式解决了这个问题,2)与Erlang大致相同。 以下是针对节点的基准: http : //www.yesodweb.com/blog/2011/03/preliminary-warp-cross-language-benchmarks

给Haskell 4核心,它可以做一个单一的应用程序每秒100k(简单)的请求。 节点无法做到这么多,也无法跨核心扩展单个应用程序。 而且你不需要做任何事情来获得这个,因为Haskell运行时是非阻塞的。 在运行时内置非阻塞IO的唯一另一种(相对常见的)语言是Erlang。

恕我直言,事件是好的,但通过callback手段是不是。

大多数使Web应用程序的编码和debugging特别困难的问题都来自可扩展性和灵活性。 HTTP的最重要的,无状态的本质。 这增强了可导航性,但是这在IO元素(在这种情况下是web服务器)在应用程序代码中调用不同处理程序的地方实施了控制反转。 这种事件模型(或称callback模型)更准确地说是一场噩梦,因为callback不共享可变范围,导航的直观视图丢失。 当用户来回导航等等时,防止所有可能的状态变化是非常困难的。

可以说,这些问题与事件模型运行良好的GUI编程类似,但是GUI没有导航和后退button。 这可以在Web应用程序中使状态转换成倍增长。 试图解决这些问题的结果是重型框架,具有复杂的configuration大量的普遍的魔法标识符,而不会质疑问题的根源:callback模型及其固有的variables范围共享缺乏,没有sorting,所以序列必须通过链接标识符来构造。

有像ocsigen(ocaml)seaside(smalltalk)WASH(停止使用,Haskell)和mflow(Haskell)这样的顺序框架来解决状态pipe理问题,同时保持适航性和REST满度。 在这些框架内,程序员可以将导航expression为一个命令序列,程序在单个线程中发送页面并等待响应,variables在范围内,后退button自动工作。 这固有地产生了更短,更安全,更易读的代码,导航程序员清晰可见。 (公平的警告:我是mflow的开发者)

就像nodejs已经放弃了解锁一样 , Snap Haskell Web Framework也放弃了libev 。