解析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打包工具整合到鼠标右键的方法
May 11 NodeJs
Nodejs进程管理模块forever详解
Jun 01 NodeJs
基于NodeJS的前后端分离的思考与实践(一)全栈式开发
Sep 26 NodeJs
nodejs中操作mysql数据库示例
Dec 20 NodeJs
使用DNode实现php和nodejs之间通信的简单实例
Jul 06 NodeJs
nodejs开发——express路由与中间件
Mar 24 NodeJs
NodeJs模拟登陆正方教务
Apr 28 NodeJs
docker中编译nodejs并使用nginx启动
Jun 23 NodeJs
Windows下使用Nodejs运行js的方法
Sep 02 NodeJs
在NodeJs中使用node-schedule增加定时器任务的方法
Jun 08 NodeJs
使用nodejs实现JSON文件自动转Excel的工具(推荐)
Jun 24 NodeJs
一文秒懂nodejs中的异步编程
Jan 28 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
世界第一个无线广播电台 KDKA
2021/03/01 无线电
php递归调用删除数组空值元素的方法
2015/04/28 PHP
laravel5.5安装jwt-auth 生成token令牌的示例
2019/10/24 PHP
jQuery textarea的长度进行验证
2009/05/06 Javascript
JavaScript对象之间的转换 jQuery对象和原声DOM
2011/03/07 Javascript
jQuery层次选择器选择元素使用介绍
2013/04/18 Javascript
详解jquery uploadify 上传文件
2013/11/09 Javascript
如何从jQuery的ajax请求中删除X-Requested-With
2013/12/11 Javascript
全面解析Javascript无限添加QQ好友原理
2016/06/15 Javascript
JavaScript正则表达式实例详解
2016/10/16 Javascript
AngularJS ionic手势事件的使用总结
2017/08/09 Javascript
nodejs用gulp管理前端文件方法
2018/06/24 NodeJs
详解Angular如何正确的操作DOM
2018/07/06 Javascript
vue cli使用融云实现聊天功能的实例代码
2019/04/19 Javascript
vue.js实现左边导航切换右边内容
2019/10/21 Javascript
[04:11]DOTA2亚洲邀请赛小组赛第一日 TOP10精彩集锦
2015/01/30 DOTA
解决pandas.DataFrame.fillna 填充Nan失败的问题
2018/11/06 Python
梅尔频率倒谱系数(mfcc)及Python实现
2019/06/18 Python
python写入数据到csv或xlsx文件的3种方法
2019/08/23 Python
pyhton中__pycache__文件夹的产生与作用详解
2019/11/24 Python
深入理解Tensorflow中的masking和padding
2020/02/24 Python
Python更换pip源方法过程解析
2020/05/19 Python
为什么说python适合写爬虫
2020/06/11 Python
利用PyQt5+Matplotlib 绘制静态/动态图的实现代码
2020/07/13 Python
五分钟带你搞懂python 迭代器与生成器
2020/08/30 Python
python3中编码获取网页的实例方法
2020/11/16 Python
机械专业毕业生推荐信范文
2013/11/25 职场文书
仓库理货员岗位职责
2013/12/18 职场文书
2014婚礼司仪主持词
2014/03/14 职场文书
商场主管竞聘书
2014/03/31 职场文书
《高尔基和他的儿子》教学反思
2014/04/09 职场文书
三年级评语大全
2014/04/23 职场文书
低碳日宣传活动总结
2014/07/09 职场文书
感恩信:写给爸爸妈妈的一封感谢信
2019/09/12 职场文书
如何使用CocosCreator对象池
2021/04/14 Javascript
总结python多进程multiprocessing的相关知识
2021/06/29 Python