Node.js中的對象池

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,766評論 18 399
  • 上文“走進Node.js啟動過程”中我們算是成功入門了。既然Node.js的強項是處理網絡請求,那我們就來分析一個...
    滬江技術學院閱讀 3,419評論 0 15
  • 我做過孤單的事 一個人吃飯 一個人逛街 一個人看電影 一個人坐車 一個人去書店看書 買一個人的單 享受一個人的時光。
    dongseang閱讀 253評論 0 0
  • 【你聽過最能引起共鳴的話是什么?】照幽怪:關于孤獨 樓下一個男人病得要死,那間壁的一家唱著留聲機,對面是弄孩子。樓...
    空歡喜大柯基閱讀 177評論 0 0
  • 投射最近出車順利。每天的客人爆滿!一天可以賺500塊。宇宙爸爸完成我的心愿
    芬芳花盛開閱讀 141評論 0 0