Page 152 - Node.js开发指南
P. 152
6.4 Node.js 不是银弹 145
Node.js 解决。 1
所以现在就让我们来谈谈 Node.js 不适合做的事情吧。
1. 计算密集型的程序
在Node.js 0.8 版本之前,Node.js 不支持多线程。当然,这是一种设计哲学问题,因为
Node.js的开发者和支持者坚信单线程和事件驱动的异步式编程比传统的多线程编程运行效 2
率更高。但事实上多线程可以达到同样的吞吐量,尽管可能开销不小,但不必为多核环境进
行特殊的配置。相比之下,Node.js 由于其单线程性的特性,必须通过多进程的方法才能充
分利用多核资源。
3
理想情况下,Node.js单线程在执行的过程中会将一个CPU核心完全占满,所有的请求必
须等待当前请求处理完毕以后进入事件循环才能响应。如果一个应用是计算密集型的,那么
除非你手动将它拆散,否则请求响应延迟将会相当大。例如,某个事件的回调函数中要进行
复杂的计算,占用CPU 200毫秒,那么事件循环中所有的请求都要等待200毫秒。为了提高 4
响应速度,你唯一的办法就是把这个计算密集的部分拆成若干个逻辑,这给编程带来了额外
的复杂性。即使这样,系统的总吞吐量和总响应延迟也不会降低,只是调度稍微公平了一些。
不过好在真正的Web 服务器中,很少会有计算密集的部分,如果真的有,那么它不应该
被实现为即时的响应。正确的方式是给用户一个提示,说服务器正在处理中,完成后会通知 5
用户,然后交给服务器的其他进程甚至其他专职的服务器来做这件事。
2. 单用户多任务型应用
前面我们讨论的通常都是服务器端编程,其中一个假设就是用户数量很多。但如果面对 6
的是单用户,譬如本地的命令行工具或者图形界面,那么所谓的大量并发请求就不存在了。
于是另一个恐怖的问题出现了,尽管是单用户,却不一定是单任务。例如给用户提供界面的
同时后台在进行某个计算,为了让用户界面不出现阻塞状态,你不得不开启多线程或多进程。
而Node.js 线程或进程之间的通信到目前为止还很不便,因为它根本没有锁,因而号称不会 7
死锁。Node.js 的多进程往往是在执行同一任务,通过多进程利用多处理器的资源,但遇到
多进程相互协作时,就显得捉襟见肘了。
3. 逻辑十分复杂的事务
Node.js 的控制流不是线性的,它被一个个事件拆散,但人的思维却是线性的,当你试 8
图转换思维来迎合语言或编译器时,就不得不作出牺牲。举例来说,你要实现一个这样的逻
辑:从银行取钱,拿钱去购买某个虚拟商品,买完以后加入库存数据库,这中间的任何一步
都可能会涉及数十次的I/O操作,而且任何一次操作失败以后都要进行回滚操作。这个过程 9
是线性的,已经很复杂了,如果要拆分为非线性的逻辑,那么其复杂程度很可能就达到无法
维护的地步了。
Node.js更善于处理那些逻辑简单但访问频繁的任务,而不适合完成逻辑十分复杂的
工作。 10