解析NodeJS异步I/O的实现


Posted in NodeJs onApril 13, 2017

在现在的项目开发中,任何一个大型项目绝对不是简简单单的采用一个种语言和一种框架,因为每种语言和框架各有优势,与其死守一个,不与取各家之所长,依次得到一个高性能、搞扩展的产品。

对于一个.NET开发者,尤其是主要从事Web开发的.NET程序员,个人觉得有必要学习一门性能优越的Web平台开发语言。一个开发者不能简简单单的只学习一门语言,思维应该开阔,从各个方面去看待同样的一个问题,这样或许会得到另一番效果和见解,个人认为应该学习一下其他的语言,这样有利于我们对比语言的优势和缺点,例如java、nodejs、python等等。对于Nodejs这个JavaScript平台,个人觉得.NET程序员有必要学习一下,因为学习NodeJS有助于我们构建一个高性能的Web平台。

NodeJS具有事件驱动、非阻塞I/O等特点,可以很好的处理I/O操作。Node面向网络且擅长并行I/O,能够有效地组织起更多的硬件资源。

这篇博客就来简单的介绍一下NodeJS的异步I/O特点。

一.NodeJS概述:

要学习一个语言或者平台,我们首先应该知道其定义,依据定义来扩展我们的学习思路。Node的定义:”一个大奖在Chrome JavaScript运行时上的平台,用于构建高速、可伸缩的网络程序。NodeJS作为一个异步事件驱动的JavaScript运行时,旨在构建可扩展的网络应用程序。“有关nodejs的背景介绍和安装方法,这里就没有必要介绍了,因为对于nodejs的安装是比较简单,所以在这里赘述就有些显得浪费时间。

学习完Node的定义特点,可能很多人都会好奇这个平台的适用场景是什么,以便在实际的项目开发中应用,不然学习这个就没有意义。主要的应用场景:前后端编程语言环境统一;高性能I/O用于实时应用;并行I/O使得使用者可以更高效地利用分布式环境;并行I/O有效利用稳定接口提升Web渲染能力;云平台的支持;游戏开发(这可能是很多开发者在意的,毕竟现在的游戏开发火热程度已经到了无以附加的地步);工具类应用,与较多的工具方法,使得开发效率大大的提升。

NodeJS异步I/O模型的基本要素:事件循环、观察者、请求对象、I/O线程池这四个共同构成。接下来我们具体了解一下这些知识。

二.NodeJS异步I/O解析:

对于Nginx服务器,很多人都是比较的熟悉,Nginx采用纯C编写而成,用于做Web服务器,在反向代理和负载均衡等服务方面有很好的优势。Node与Nginx服务器有着相似的地方,都是采用事件驱动。

浏览器中JavaScript在单线程上执行,而且还与UI渲染共用一个线程,JavaScript在执行的时候UI渲染和响应应是出于停滞状态。(如果脚本执行的时间超过100毫秒,用户就会感到页面卡顿)。遇到这些情况,我们就会想到异步的方式消除这些等待的问题,对于异步和同步的概念就不做介绍了。

=接下来我们具体的来了解一下NodeJS的事件驱动和非阻塞I/O这些特点,了解这些对于我们更好的学习NodeJS开发和构建高性能的Web平台有更加深远的意义。

1.I/O操作概述:

I/O操作对于任何一个开发者来说都不会陌生,现在我们就简单的谈一下NodeJS的I.O操作。I/O操作分为:单线程串行依次执行;多线程并行执行。这两种方式各有优势和缺点,多线程的代价在于创建线程和执行期线程上下文切换的开销较大,并且多线程面临锁、状态同步的问题。单线程安装顺序执行,在执行中任何一个稍慢都会导致后续执行代码阻塞。对于任务的串行执行(概念上类似于同步执行)和任务的并行执行的描述有如下图:

解析NodeJS异步I/O的实现解析NodeJS异步I/O的实现 

          

在NodeJS中利用单线程,远离死锁、状态同步问题,利用异步I/O,让单线程远离阻塞,以便更好的使用CPU。异步I/O是期望I/O的调用不再阻塞后续运算,将原有等待I/O完成这段时间分配给其他需要的业务去执行。

 

很多时候一些开发者对异步/同步和阻塞/非阻塞的概念有些分不清,这两者没有什么关联。阻塞I/O是调用之后一定要等到系统内核层面完成所有操作后,调用才结束。非阻塞I/O是在调用后立即返回。关于阻塞I/O和非阻塞I/O有如下图:

 解析NodeJS异步I/O的实现解析NodeJS异步I/O的实现

2.NodeJS异步I/O解析:

事件循环:在进程启动时,Node会创建一个类似于while(true)的循环,每执行一次循环体的过程称为Tick,每个Tick的过程就是查看是否有时间待处理。

观察者:每个时间循环中有一个或多个观察者,判断是否有事件要处理的过程就是向这些观察者询问是否又要处理的事件。

请求对象:从JavaScript发起调用到内核执行完I/O操作的过渡过程中,存在一种中间产物,就是请求对象。

I/O线程池:组装好请求、送入I/O线程池等待执行,完成第一步I/O操作,进入第二部分回调通知。(在Windows中,线程池中的I/O操作调用完毕之后,会将获取的结果存在req->result属性上,然后调用PostQueuedCompletionStatus()通知IOCP,告知当前对象操作已经完成。)

异步I/O有如下图:

解析NodeJS异步I/O的实现

三.NodeJS异步编程实例:

前面介绍了异步I/O的相关概念,这里提供一个异步I/O操作的实例:

var config = require('./config.json');
var fs = require("fs");
var http = require('http');
var url_module = require("url");

http.createServer(function (request, response) {
  var key = url_module.parse(request.url).query.replace('key=', '');
  switch (request.method) {
    case 'GET': // Asynchronous Response Generation
      fs.readFile(config.dataPath + key, 'utf8', function(err, value) {
        if (err) {
          // Return File Not Found if file hasn't yet been created
          response.writeHead(404, {'Content-Type': 'text/plain'});
          response.end("The file (" + config.dataPath + key + ") does not yet exist.");
        } else {
          // If the file exists, read it and return the sorted contents
          var sorted = value.split(config.sortSplitString).sort().join('');
          response.writeHead(200, {'Content-Type': 'text/plain'});
          response.end(sorted);
        }
      });
      break;
    case 'POST': // Synchronously append POSTed data to a file
      var postData = '';
      request
        .on('data', function (data) {
          postData += data;
        })
        .on('end', function () {
          fs.appendFile(config.dataPath + key, postData, function(err) {
            if (err) {
              // Return error if unable to create/append to the file
              response.writeHead(400, {'Content-Type': 'text/plain'});
              response.end('Error: Unable to write file: ' + err);
            } else {
              // Write or append posted data to a file, return "success" response
              response.writeHead(200, {'Content-Type': 'text/plain'});
              response.end('success');
            }
          });
        });
      break;
    default:
      response.writeHead(400, {'Content-Type': 'text/plain'});
      response.end("Error: Bad HTTP method: " + request.method);
  }
}).listen(config.serverPort);

console.log('synchronous server is running: ', config.serverPort);

四.总结:

这篇博文是个人初次尝试NodeJS的一个小总结,如有写的不好还望大家多多的包含和指正。对于程序员来说,需要做的就是一直不停的学习,无论是否是自己主要从事的语言,对于学习多种语言,可以更加有助我们了解编程,对于一个开发者来说,最终的就是思想,因为语言的特性和框架的应用,一个熟练的编程者学习起来并不是难事,难就难在我们对于语言和框架的设计理念的理解。

NodeJs 相关文章推荐
nodejs命令行参数处理模块commander使用实例
Sep 17 NodeJs
nodejs 提示‘xxx’ 不是内部或外部命令解决方法
Nov 20 NodeJs
NodeJS学习笔记之Http模块
Jan 13 NodeJs
NodeJS中利用Promise来封装异步函数
Feb 25 NodeJs
Nodejs学习笔记之入门篇
Apr 16 NodeJs
nodejs个人博客开发第一步 准备工作
Apr 12 NodeJs
nodeJs实现基于连接池连接mysql的方法示例
Feb 10 NodeJs
nodejs+express搭建多人聊天室步骤
Feb 12 NodeJs
Linux Centos7.2下安装nodejs&npm配置全局路径的教程
May 15 NodeJs
Nodejs模块的调用操作实例分析
Dec 25 NodeJs
NodeJs入门教程之定时器和队列
Mar 08 NodeJs
Nodejs + Websocket 指定发送及群聊的实现
Jan 09 NodeJs
详解nodejs微信公众号开发——6.自定义菜单
Apr 13 #NodeJs
nodejs个人博客开发第七步 后台登陆
Apr 12 #NodeJs
nodejs个人博客开发第六步 数据分页
Apr 12 #NodeJs
nodejs个人博客开发第五步 分配数据
Apr 12 #NodeJs
nodejs个人博客开发第四步 数据模型
Apr 12 #NodeJs
nodejs个人博客开发第三步 载入页面
Apr 12 #NodeJs
nodejs个人博客开发第二步 入口文件
Apr 12 #NodeJs
You might like
如何对PHP程序中的常见漏洞进行攻击
2006/10/09 PHP
PHP中的cookie
2006/11/26 PHP
php之字符串变相相减的代码
2007/03/19 PHP
php在程序中将网页生成word文档并提供下载的代码
2012/10/09 PHP
PHP面向对象程序设计之构造方法和析构方法详解
2019/06/13 PHP
javascript编程起步(第四课)
2007/01/10 Javascript
一句话JavaScript表单验证代码
2009/08/02 Javascript
自己写的兼容ie和ff的在线文本编辑器类似ewebeditor
2012/12/12 Javascript
基于pthread_create,readlink,getpid等函数的学习与总结
2013/07/17 Javascript
js获取select标签的值且兼容IE与firefox
2013/12/30 Javascript
jquery ajax应用中iframe自适应高度问题解决方法
2014/04/12 Javascript
JavaScript数组方法总结分析
2016/05/06 Javascript
JavaScript实现刷新不重记的倒计时
2016/08/10 Javascript
jQuery的三种bind/One/Live/On事件绑定使用方法
2017/02/23 Javascript
jQuery实现简单的滑动导航代码(移动端)
2017/05/22 jQuery
使用vue-cli+webpack搭建vue开发环境的方法
2017/12/22 Javascript
浅析从vue源码看观察者模式
2018/01/29 Javascript
vue-cli项目根据线上环境分别打出测试包和生产包
2018/05/23 Javascript
Vue项目中使用better-scroll实现菜单映射功能方法
2019/09/11 Javascript
jQuery实现简单评论功能
2020/08/19 jQuery
[57:22]完美世界DOTA2联赛PWL S2 FTD vs PXG 第二场 11.27
2020/12/01 DOTA
python使用pil生成缩略图的方法
2015/03/26 Python
Python基于百度AI的文字识别的示例
2018/04/21 Python
Python判断两个文件是否相同与两个文本进行相同项筛选的方法
2019/03/01 Python
python控制nao机器人身体动作实例详解
2019/04/29 Python
如何使用Python实现自动化水军评论
2019/06/26 Python
对于Python深浅拷贝的理解
2019/07/29 Python
python查看数据类型的方法
2019/10/12 Python
python 实现保存最新的三份文件,其余的都删掉
2019/12/22 Python
python将logging模块封装成单独模块并实现动态切换Level方式
2020/05/12 Python
Python return语句如何实现结果返回调用
2020/10/15 Python
python实现控制台输出颜色
2021/03/02 Python
2014年国庆节寄语
2014/09/19 职场文书
教师自我剖析材料(四风问题)
2014/09/30 职场文书
nginx前后端同域名配置的方法实现
2021/03/31 Servers
MySQL系列之八 MySQL服务器变量
2021/07/02 MySQL