解析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制作爬虫全过程(续)
Dec 22 NodeJs
nodejs事件的监听与触发的理解分析
Feb 12 NodeJs
NodeJs中的VM模块详解
May 06 NodeJs
nodejs使用express创建一个简单web应用
Mar 31 NodeJs
浅谈nodejs中的类定义和继承的套路
Jul 26 NodeJs
nodejs 最新版安装npm 的使用详解
Jan 18 NodeJs
详解NodeJs开发微信公众号
May 25 NodeJs
nodejs 生成和导出 word的实例代码
Jul 31 NodeJs
nodejs对项目下所有空文件夹创建gitkeep的方法
Aug 02 NodeJs
nodejs一个简单的文件服务器的创建方法
Sep 13 NodeJs
详解利用nodejs对本地json文件进行增删改查
Sep 20 NodeJs
使用 Koa + TS + ESLlint 搭建node服务器的过程详解
May 30 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发送有附件的电子邮件-(PHPMailer使用的实例分析)
2013/04/26 PHP
php实现二叉树中和为某一值的路径方法
2018/10/14 PHP
js 动态添加标签(新增一行,其实很简单,就是几个函数的应用)
2009/03/26 Javascript
页面加载完成后再执行JS的jquery写法以及区别说明
2014/02/22 Javascript
PHP PDO操作总结
2014/11/17 Javascript
node.js中的querystring.parse方法使用说明
2014/12/10 Javascript
移动设备web开发首选框架:zeptojs介绍
2015/01/29 Javascript
使用BootStrap实现用户登录界面UI
2016/08/10 Javascript
jsonp跨域请求实现示例
2017/03/13 Javascript
详解如何用babel转换es6的class语法
2018/04/03 Javascript
JS数组去重常用方法实例小结【4种方法】
2018/05/28 Javascript
详解创建自定义的Angular Schematics
2018/06/06 Javascript
微信小程序五子棋游戏的悔棋实现方法【附demo源码下载】
2019/02/20 Javascript
Vue路由 重定向和别名的区别说明
2020/09/09 Javascript
[00:37]DOTA2上海特级锦标赛 OG战队宣传片
2016/03/03 DOTA
Python使用PyGreSQL操作PostgreSQL数据库教程
2014/07/30 Python
Python利用pyHook实现监听用户鼠标与键盘事件
2014/08/21 Python
python基于multiprocessing的多进程创建方法
2015/06/04 Python
Python中shape计算矩阵的方法示例
2017/04/21 Python
利用Python操作消息队列RabbitMQ的方法教程
2017/07/19 Python
Python实现找出数组中第2大数字的方法示例
2018/03/26 Python
解决Python下imread,imwrite不支持中文的问题
2018/12/05 Python
解决Python3用PIL的ImageFont输出中文乱码的问题
2019/08/22 Python
Python3实现二叉树的最大深度
2019/09/30 Python
Jupyter notebook 远程配置及SSL加密教程
2020/04/14 Python
Python绘制动态水球图过程详解
2020/06/03 Python
python 图像判断,清晰度(明暗),彩色与黑白实例
2020/06/04 Python
CSS3中文字镂空、透明值、阴影效果设置示例小结
2016/03/07 HTML / CSS
澳大利亚最大的百货公司:Myer
2018/12/21 全球购物
德国家用电器购物网站:Premiumshop24
2019/08/22 全球购物
英国名牌男装店:Standout
2021/02/17 全球购物
资产运营委托书范本
2014/10/16 职场文书
2015年爱牙日活动总结
2015/03/23 职场文书
撤诉申请书法院范本
2015/05/18 职场文书
中学生运动会广播稿
2015/08/19 职场文书