Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Node.js 之对象池 #1

Open
hustxiaoc opened this issue May 14, 2014 · 9 comments
Open

Node.js 之对象池 #1

hustxiaoc opened this issue May 14, 2014 · 9 comments

Comments

@hustxiaoc
Copy link
Owner

大家都知道用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 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

@zhangxiaov
Copy link

thanks!

@hustxiaoc
Copy link
Owner Author

@zhangxiaov 不客气~

@scfobao
Copy link

scfobao commented Dec 3, 2016

@hustxiaoc 看起来非常不错,我是个新手,目前也遇到并发问题,不知道如何能将其应用到实际场景中。

@hustxiaoc
Copy link
Owner Author

@scfobao 你是什么场景呢

@onszzo
Copy link

onszzo commented Jan 23, 2017

@hustxiaoc 新手路过,照着书上的例子,愣是什么都没弄出来,到处报错,郁闷呀,跪求大神带我飞飞飞...

@hustxiaoc
Copy link
Owner Author

@onszzo 可以贴下你的代码么

@MsWangyouhui
Copy link

虽然目前没用到。但还是不得不赞一个。

@Vibing
Copy link

Vibing commented Dec 18, 2017

good!

@fushome
Copy link

fushome commented Feb 26, 2018

谢谢分享啊,新手程序员留

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants