Happy Coding, Happy Life

Node.js Learning Summary

| Comments

一直以来,我对Javascript都不是怎么感兴趣,主要的原因还是由于JavaScript 和浏览器之间复杂的历史渊源,导致javascript被浏览器严重束缚。 不过,Node.js的出现,让我看到了一种全新的使用JS的方式(启动、调试等可以完全不care浏览器)。经过几天对Node的了解,发现Node确实有一些与众不同的特点。

1. 什么是Node.js

Node.js诞生于2009年, 是一个可以让 JavaScript 运行在服务器端的平台。通过使用Node.js, JavaScript能够脱离浏览器的束缚,运行在独立的服务器环境下, 就像运行 Python、Perl、PHP、Ruby 程序一样。除此之外,Node.js 可以作为web服务器直接运行Node的应用, 与 PHP、Python、Ruby on Rails 相比, 它省去了 Apache、Nginx 等 HTTP 服务器的搭建。 Node.js摒弃了传统平台依靠多线程来实现高并发的设计思路,采用了单线程、异步式I/O、事件驱动式的程序模型,因此不仅带来了性能的提升,而且还减少了多线程程序设计的复杂性(同步、互斥等),提高了开发效率。 虽然Node.js的年龄不大,可影响力不小。目前已经有很多来自官方或者社区提供的Node模块,例如网站开发框架、访问MySQL、MongoDB等的数据库接口、模版引擎等等, Node逐渐形成了一个庞大的,愈趋成熟的生态系统。

2. Node.js能做什么

Node.js 内建了 HTTP 服务器支持,也就是说你可以轻而易举地实现一个网站和服务器的组合。当然,Node.js 能做的远不止开发一个网站那么简单,使用 Node.js,你可以轻松地开发: a) 具有复杂逻辑的网站; b) Web Socket 服务器; c) 命令行工具; d) 带有图形用户界面的本地应用程序; e) 单元测试工具; 等等。

3.采用异步式 I/O与事件驱动的编程模型

异步I/O

什么是同步式I/O?

当线程在执行中遇到磁盘读写或网络通信(统称为 I/O 操作),通常要耗费较长的时间,这时操作系统会剥夺这个线程的CPU控制权,使其暂停执行,同时将资源让给其他的工作线程,这种线程调度方式称为阻塞。当I/O操作完毕时,操作系统将这个线程的阻塞状态解除,恢复其对CPU的控制权,令其继续执行。这种I/O模式就是通常的同步式 I/O(Synchronous I/O或阻塞式 I/O (Blocking I/O)。

什么是异步式I/O?

异步式 I/O (Asynchronous I/O)或非阻塞式 I/O (Non-blocking I/O)则针对所有I/O操作不采用阻塞的策略。当线程遇到I/O操作时,不会以阻塞的方式等待I/O操作的完成或数据的返回,而只是将 I/O请求发送给操作系统,继续执行下一条语句。当操作系统完成I/O操作时,以事件的形式通知执行I/O操作的线程,线程会在特定时候处理这个事件。

二者的区别?

在阻塞模式下,一个线程只能处理一项任务,要想提高吞吐量必须通过多线程。在阻塞模式下,多线程往往能提高系统吞吐量,因为一个线程阻塞时还有其他线程在工作,多线程可以让CPU资源不被阻塞中的线程浪费。在非阻塞模式下,一个线程永远在执行计算操作。在非阻塞模式 下,线程不会被 I/O 阻塞,永远在利用 CPU。

简而言之, 异步式I/O就是少了多线程的开销。对操作系统来说,创建一个线程的代价是十分昂贵的,需要给它分配内存、列入调度,同时在线程切换的时候还要执行内存换页,CPU的缓存被清空,切换回来的时候还要重新从内存中读取信息,破坏了数据的局部性。因此,多线程带来的好处仅仅是在多核 CPU 的情况下利用更多的核,而Node.js使用单线程也能带来同样的好处。这就是为什么 Node.js使用单线程、非阻塞的事件编程模式。

事件驱动

Node.js的异步机制是基于事件的,所有的磁盘I/O、网络通信、数据库查询都以非阻塞的方式请求,返回的结果由事件回调来处理。Node.js 在同一时 刻只会处理一个事件,完成后立即进入事件循环检查并处理后面的事件。这样做的好处是, CPU 和内存在同一时间集中处理一件事,同时尽可能让耗时的I/O操作并行执行。因为Node.js只是在事件队列中增加请求,等待操作系统的回应,因而不会有任何多线程开销,很大程度上可以提高 Web 应用的健壮性,并防止恶意攻击。

Node.js在什么时候会进入事件循环呢?

Node.js程序由事件循环开始,到事件循环结束,所有的逻辑都是事件的回调函数,所以 Node.js 始终在事件循环中,程序入口就是 事件循环第一个事件的回调函数。事件的回调函数在执行的过程中,可能会发出 I/O 请求或 直接发射(emit)事件,执行完毕后再返回事件循环,事件循环会检查事件队列中有没有未 处理的事件,直到程序结束。

4.总结

Node.js最大的特点就是异步式I/O(或者非阻塞I/O)与事件紧密结合的编程模式。这种方式带来了可观的性能提升,与此同时,这种异步事件模式的弊端也是显而易见的,因为它不符合开发者的常规线性思路,往往需要把一个完整的逻辑拆分为一个个事件,并使用回调进行处理,这无疑增加了开发和调试难度,在后续的部分中,我会继续关注Node.js的其他部分。

5. 参考

http://code.danyork.com/2011/01/25/node-js-doctors-offices-and-fast-food-restaurants-understanding-event-driven-programming/

Comments