1、为什么叫Node?
它自身非常简单,通过通信协议来组织很多Node,非常容易通过扩展来达成构建大型网络应用的目的。每一个Node进程都构成这个网络应用中的一个节点,这是它名字所含意义的真谛。
2、你能说说Node的特点吗?
作为后端JavaScript的运行平台,Node保留了前端浏览器JavaScript中那些熟悉的接口,没有改写语言本身的任何特性,依旧基于作用域和原型链,区别在于它将前端中广泛运用的思想迁移到了服务器端。下面我们可以看看node相较于其他语言的一些特点:
(1)异步I/O
关于异步I/O,向前端工程师解释起来或许会容易一些,因为发起Ajax调用对于前端工程师而言是再熟悉不过的场景了。下面的代码用于发起一个Ajax请求:
- $.post('/url', {title: ’深入浅出Node.js'}, function (data) {
- console.log(’收到响应’);
- });
- console.log(’发送Ajax结束’);
熟悉异步的用户必然知道,“收到响应”是在“发送Ajax结束”之后输出的。在调用$.post()后,后续代码是被立即执行的,而“收到响应”的执行时间是不被预期的。我们只知道它将在这个异步请求结束后执行,但并不知道具体的时间点。异步调用中对于结果值的捕获是符合“Don't call me, I will call you”的原则的,这也是注重结果,不关心过程的一种表现。
(2)事件与回调函数
Node不像Rhino那样受Java的影响很大,而是将前端浏览器中应用广泛且成熟的事件引入后端,配合异步I/O,将事件点暴露给业务逻辑。
相比之下,无论在前端还是后端,事件都是常用的。对于其他语言来说,这种俯拾皆是JavaScript的熟悉感觉是基本不会出现的。
(3)单线程
Node保持了JavaScript在浏览器中单线程的特点。而且在Node中,JavaScript与其余线程是无法共享任何状态的。
单线程的最大好处是不用像多线程编程那样处处在意状态的同步问题,这里没有死锁的存在,也没有线程上下文交换所带来的性能上的开销。
同样,单线程也有它自身的弱点,这些弱点是学习Node的过程中必须要面对的。积极面对这些弱点,可以享受到Node带来的好处,也能避免潜在的问题,使其得以高效利用。单线程的弱点具体有以下3方面。
- ❑ 无法利用多核CPU。
- ❑ 错误会引起整个应用退出,应用的健壮性值得考验。
- ❑ 大量计算占用CPU导致无法继续调用异步I/O。
像浏览器中JavaScript与UI共用一个线程一样,JavaScript长时间执行会导致UI的渲染和响应被中断。在Node中,长时间的CPU占用也会导致后续的异步I/O发不出调用,已完成的异步I/O的回调函数也会得不到及时执行。
3、上面提到单线程不利于计算,无法利用多核cpu,难道没有解决方法吗?
有的。
Node采用了与Web Workers相同的思路来解决单线程中大计算量的问题:child_process。
子进程的出现,意味着Node可以从容地应对单线程在健壮性和无法利用多核CPU方面的问题。通过将计算分发到各个子进程,可以将大量计算分解掉,然后再通过进程之间的事件消息来传递结果,这可以很好地保持应用模型的简单和低依赖。
4、那你可以谈谈node的使用场景吗?
关于Node,探讨得较多的主要有I/O密集型和CPU密集型。
I/O密集型
在Node的推广过程中,无数次有人问起Node的应用场景是什么。如果将所有的脚本语言拿到一处来评判,那么从单线程的角度来说,Node处理I/O的能力是值得竖起拇指称赞的。通常,说Node擅长I/O密集型的应用场景基本上是没人反对的。Node面向网络且擅长并行I/O,能够有效地组织起更多的硬件资源,从而提供更多好的服务。
I/O密集的优势主要在于Node利用事件循环的处理能力,而不是启动每一个线程为每一个请求服务,资源占用极少。
CPU密集型
换一个角度,在CPU密集的应用场景中,Node是否能胜任呢?实际上,V8的执行效率是十分高的。单以执行效率来做评判,V8的执行效率是毋庸置疑的。
CPU密集型应用给Node带来的挑战主要是:由于JavaScript单线程的原因,如果有长时间运行的计算(比如大循环),将会导致CPU时间片不能释放,使得后续I/O无法发起。但是适当调整和分解大型运算任务为多个小任务,使得运算能够适时释放,不阻塞I/O调用的发起,这样既可同时享受到并行异步I/O的好处,又能充分利用CPU。
CPU密集不可怕,如何合理调度是诀窍。
最后
这是我策划撰写的关于深入探讨node的系列文章