Node.js中的对象池

作者: 淘小杰 | 来源:发表于2015-09-10 22:27 被阅读312次

    大家都知道用Node.js搭建一个简单的http服务器是多么easy的事情,打开记事本贴几句脚本,ctrl+s一下,node server.js 一个http服务器就这样跑起来了,别看它简单,但性能丝毫不差。

    var http = require('http');
    http.createServer(function (req, res) {
      res.writeHead(200, {'Content-Type': 'text/plain'});
      res.end('Hello Worldn');
    }).listen(1337, '127.0.0.1');
    console.log('Server running at http://127.0.0.1:1337/');
    

    Node.js搭建的服务器性能如此给力确实让我很好奇它的内部是如何设计的,忍不住翻了翻lib下的代码。

    深入了解过Node.js http模块的同学应该知道Node.js采用一个纯c写的http_parser来实现对http报文的解析,暴露到Node.js上的是一个HTTPParser对象,在Node.js中用下面一句代码即可拿到

    var HTTPParser = process.binding('http_parser').HTTPParser;
    

    Node.js中调用c/c++内置模块采用 process.binding('module')模式,比如我们常用的setInterval和setTimeout都是基于c/c++代码实现,用 process.binding('timer_wrap').Timer即可提供js调用。

    Node.js http服务器每收到一个request就会用一个HTTPParser对象来解析出请求信息,比如请求参数,请求体之类的。如果说每接收一个request 都new 一个 HTTPParser对象来处理, 可以想象当并发达到成千上万时创建HTTPParser对象是多么的频繁,用完之后又立刻销毁,这种场景我们很容易想到利用多线程来处理耗时任务,为了避免频繁的创建销毁线程对象, 一般都会创建一个线程池来处理任务。于是Node.js中边产生了对象池这么个东西,也就是接下来要讲的freelist 。

    首先我们来看看freelist是个什么东西,和对象池有怎样的联系。

     function FreeList(name, max, constructor) {
      this.name = name;
      this.constructor = constructor;
      this.max = max;
      this.list = [];
    };
    
    
    FreeList.prototype.alloc = function() {
      return this.list.length ? this.list.shift() :
                                this.constructor.apply(this, arguments);
    };
    
    
    FreeList.prototype.free = function(obj) {
      //debug("free " + this.name + " " + this.list.length);
      if (this.list.length < this.max) {
        this.list.push(obj);
      }
    };
    

    代码相当的简单,FreeList构造函数接收3个参数,对象池名字,大小以及对象构造函数。比如在Node.js中创建一个httpParse对象池:

    var parsers = new FreeList('parsers', 1000, function() {
      var parser = new HTTPParser(HTTPParser.REQUEST);
    
      parser._headers = [];
      parser._url = '';
      parser[kOnHeaders] = parserOnHeaders;
      parser[kOnHeadersComplete] = parserOnHeadersComplete;
      parser[kOnBody] = parserOnBody;
      parser[kOnMessageComplete] = parserOnMessageComplete;
    
      return parser;
    });
    

    Node.js中用这段代码创建了一个叫parsers,大小为1000的对象池,当Node.js服务器接收到一个request时便向这个对象池索取一个HTTPParser对象即调用对象池parsers的alloc方法,此时便拿到了一个parser对象,parser对象解析完http报文后node并没有立即释放它,而是将它重新放入对象池parsers中,即调用parsers.free(parser),当然了只有当池子还没满的时候才可以重新被放进去。如此便实现了parser对象的重复利用,当并发数很高时极大的提升性能。

    Alt textAlt text

    相信小伙伴们应该都很清楚对象池的原理以及它在Node.js服务器中的作用了, 希望对大家在实际的业务中有所帮助哦~

    参考文档

    1.https://github.com/joyent/node/tree/master/deps/http_parser
    2.https://github.com/joyent/node/blob/master/lib/freelist.js

    相关文章

      网友评论

        本文标题:Node.js中的对象池

        本文链接:https://www.haomeiwen.com/subject/scypcttx.html