我相信Erlang社区并不羡慕Node.js,因为它在本地实现了非阻塞I/O,并且可以轻松地将部署扩展到多个处理器(Node.js中甚至没有内置这些处理器)。更多详情请访问http://journal.dedasys.com/2010/04/29/erlang-vs-node-js和Node.js或Erlang
哈斯克尔呢?Haskell能否提供Node.js的一些好处,即在不求助于多线程编程的情况下避免阻塞I/O的干净解决方案?
Node.js有很多吸引人的地方
Events: No thread manipulation, the programmer only provides callbacks (as in Snap framework)
Callbacks are guaranteed to be run in a single thread: no race condition possible.
Nice and simple UNIX-friendly API. Bonus: Excellent HTTP support. DNS also available.
Every I/O is by default asynchronous. This makes it easier to avoid locks. However, too much CPU processing in a callback will impact other connections (in this case, the task should split into smaller sub-tasks and re-scheduled).
Same language for client-side and server-side. (I don't see too much value in this one, however. jQuery and Node.js share the event programming model but the rest is very different. I just can't see how sharing code between server-side and client-side could be useful in practice.)
All this packaged in a single product.
IMHO事件很好,但是通过回调来编程就不好了。
Most of the problems that makes special the coding and debugging of web applications comes from what makes them scalable and flexible. The most important, the stateless nature of HTTP. This enhances navigability, but this imposes an inversion of control where the IO element (the web server in this case) call different handlers in the application code. This event model -or callback model, more accurately said- is a nightmare, since callbacks do not share variable scopes, and an intuitive view of the navigation is lost. It is very difficult to prevent all the possible state changes when the user navigate back and forth, among other problems.
It may be said that the problems are similar to GUI programming where the event model works fine, but GUIs have no navigation and no back button. That multiplies the state transitions possible in web applications. The result of the attempt to solve these problem are heavy frameworks with complicated configurations plenty of pervasive magic identifiers without questioning the root of the problem: the callback model and its inherent lack of sharing of variable scopes, and no sequencing, so the sequence has to be constructed by linking identifiers.
There are sequential based frameworks like ocsigen (ocaml) seaside (smalltalk) WASH (discontinued, Haskell) and mflow (Haskell) that solve the problem of state management while maintaining navigability and REST-fulness. within these frameworks, the programmer can express the navigation as a imperative sequence where the program send pages and wait for responses in a single thread, variables are in scope and the back button works automatically. This inherently produces shorter, more safe, more readable code where the navigation is clearly visible to the programmer. (fair warning: I´m the developer of mflow)
Haskell能否提供Node.js的一些好处,即在不求助于多线程编程的情况下避免阻塞I/O的干净解决方案?
是的,事实上事件和线程在Haskell中是统一的。
你可以在显式的轻量级线程中编程(例如,一台笔记本电脑上有数百万个线程)。
或;您可以基于可伸缩的事件通知以异步事件驱动风格进行编程。
线程实际上是根据事件实现的,并跨多个核心运行,具有无缝的线程迁移,有记录的性能和应用程序。
例如
大规模并发工作编排
并发集合在32或48核上扩展
工具支持分析和调试多线程/多事件程序。
高性能事件驱动的web服务器。
有趣的用户:比如高频交易。
并发收集nbody在32核
在Haskell中,你同时拥有事件和线程,因为它是所有事件的底层。
阅读描述实现的论文。
Ok, so having watched a little of the node.js presentation that @gawi pointed me at, I can say a bit more about how Haskell compares to node.js. In the presentation, Ryan describes some of the benefits of Green Threads, but then goes on to say that he doesn't find the lack of a thread abstraction to be a disadvantage. I'd disagree with his position, particularly in the context of Haskell: I think the abstractions that threads provide are essential for making server code easier to get right, and more robust. In particular:
using one thread per connection lets you write code that expresses the communication with a single client, rather that writing code that deals with all the clients at the same time. Think of it like this: a server that handles multiple clients with threads looks almost the same as one that handles a single client; the main difference is there's a fork somewhere in the former. If the protocol you're implementing is at all complex, managing the state machine for multiple clients simultaneously gets quite tricky, whereas threads let you just script the communication with a single client. The code is easier to get right, and easier to understand and maintain.
callbacks on a single OS thread is cooperative multitasking, as opposed to preemptive multitasking, which is what you get with threads. The main disadvantage with cooperative multitasking is that the programmer is responsible for making sure that there's no starvation. It loses modularity: make a mistake in one place, and it can screw up the whole system. This is really something you don't want to have to worry about, and preemption is the simple solution. Moreover, communication between callbacks isn't possible (it would deadlock).
concurrency isn't hard in Haskell, because most code is pure and so is thread-safe by construction. There are simple communication primitives. It's much harder to shoot yourself in the foot with concurrency in Haskell than in a language with unrestricted side effects.
IMHO事件很好,但是通过回调来编程就不好了。
Most of the problems that makes special the coding and debugging of web applications comes from what makes them scalable and flexible. The most important, the stateless nature of HTTP. This enhances navigability, but this imposes an inversion of control where the IO element (the web server in this case) call different handlers in the application code. This event model -or callback model, more accurately said- is a nightmare, since callbacks do not share variable scopes, and an intuitive view of the navigation is lost. It is very difficult to prevent all the possible state changes when the user navigate back and forth, among other problems.
It may be said that the problems are similar to GUI programming where the event model works fine, but GUIs have no navigation and no back button. That multiplies the state transitions possible in web applications. The result of the attempt to solve these problem are heavy frameworks with complicated configurations plenty of pervasive magic identifiers without questioning the root of the problem: the callback model and its inherent lack of sharing of variable scopes, and no sequencing, so the sequence has to be constructed by linking identifiers.
There are sequential based frameworks like ocsigen (ocaml) seaside (smalltalk) WASH (discontinued, Haskell) and mflow (Haskell) that solve the problem of state management while maintaining navigability and REST-fulness. within these frameworks, the programmer can express the navigation as a imperative sequence where the program send pages and wait for responses in a single thread, variables are in scope and the back button works automatically. This inherently produces shorter, more safe, more readable code where the navigation is clearly visible to the programmer. (fair warning: I´m the developer of mflow)