自己随便写的一个对象池 - CNode技术社区

自己随便写的一个对象池
发布于 13 年前 作者 saber 9915 次浏览 最后一次编辑是 9 年前

坛子里有人发了篇]mongodb驱动的正确使用方法,里面通过对象池来解决的思路很正确,文中提到用了现有的generic_pool模块,这里我发一个自己写的简单对象池,只所以自己写是我觉得generic_pool可能没解决一个开发过程中可以忽略不计的失误, 就是当开发人员忘了在操作结束调用pool.release,这个问题在现实中可能大家都不会犯,但谁又能肯定在半夜昏昏沉沉的时候就偏偏漏掉呢,一旦忘了释放, 对象池就会源源不断打开新的链接, 所以我就写了一个简单的对象池模块, 运行下来效果还行

先对Array做一些扩展

Array.prototype.where = function(whereFunc){
 var tmp = [];
 this.forEach(function(element){
 if (whereFunc(element)){
 tmp.push(element);
 }
 });
 return tmp;
};
Array.prototype.remove = function(element){
 var elementIndex = this.indexOf(element);
 if(elementIndex > -1){
 this.splice(elementIndex, 1);
 }
};

ObjectPool.js

function objectPool(option){
 var totalObjCount = 0;
 var objectPool={
 free:[],
 busy:[]
 };
 /**
 * 从对象池中获取一个对象,当没有可用的对象时候创建新的对象
 * */
 this.getOne = function(){
 if(objectPool.free.length > 0) {
 var obj = objectPool.free.pop();
 obj.startBusyTime = new Date();
 objectPool.busy.push(obj);
 return obj;
 }
 else {
 var newObj = option.objectCreate();
 totalObjCount++;
 newObj.startBusyTime = new Date();
 objectPool.busy.push(newObj);
 return newObj;
 }
 };
 //释放对象池中的对象
 this.freeOne = function(obj){
 var elementIndex = objectPool.busy.indexOf(obj);
 if(elementIndex > -1){
 objectPool.busy.remove(obj);
 objectPool.free.push(obj);
 }
 };
 this.init = function(){
 //对象池中的对象小于最小数
 if(totalObjCount < option.minConnect) {
 for(var i=totalObjCount; i<totalObjCount; i++){
 var newObj = option.objectCreate();
 totalObjCount++;
 objectPool.free.push(newObj);
 }
 }
 };
 //对象池维护函数,防止产生过多的对象
 this.manager = function(){
 if(!this.managerTimmer){
 this.managerTimmer = setInterval(function(){
 //将超过最大忙碌时间的对象挪回空闲队列
 var needToFreeObjs = objectPool.busy.where(function(o){
 var now = new Date();
 if((now - o.startBusyTime) >= option.maxBusyTime)
 return true;
 else
 return false;
 });
 needToFreeObjs.forEach(function(o){
 this.freeOne(o);
 }.bind(this));
 //产生的对象数已经超过最大限制数,且有空闲对象,可以将空闲对象释放
 if(totalObjCount > option.maxConnect && objectPool.free.length > 0) {
 for(var i=totalObjCount; i>option.maxConnect && objectPool.free.length > 0; i--){
 var obj = objectPool.free.pop();
 totalObjCount--;
 option.objectRelease(obj);
 }
 }
 }.bind(this), option.managerSpan*1000);
 }
 };
 //销毁对象池,释放所有对象
 this.destroy = function(){
 objectPool.free.forEach(function(obj){
 option.objectRelease(obj);
 });
 objectPool.free = Array.Empty();
 objectPool.busy.forEach(function(obj){
 option.objectRelease(obj);
 });
 objectPool.busy = Array.Empty();
 totalObjCount = 0;
 };
}
module.exports = exports = objectPool;

使用方法,我用的是Mongoskin

var mongoSkin = require('mongoskin');
var objectPool = require('./ObjectPool.js');
var mongo = {
 hostname:'127.0.0.1',
 port:27017,
 db:'test'
};
var generate_mongo_url = function(obj){
 obj.hostname = obj.hostname || 'localhost';
 obj.port = obj.port || 27017;
 obj.db = obj.db || 'test';
 if(obj.username && obj.password){
 return obj.username + ':' + obj.password + '@' + obj.hostname + ':' + obj.port + '/' + obj.db;
 }
 else {
 return obj.hostname + ':' + obj.port + '/' + obj.db;
 }
};
var poolOption={
 minConnect:5,
 maxConnect:50,
 managerSpan:120, //对象池维护周期,单位秒
 maxBusyTime:60000, //最大工作时间,超过这个时间说明开发人员可能漏了释放资源
 objectCreate:function(){
 return mongoSkin.db(generate_mongo_url(mongo));
 },
 objectRelease:function(obj){
 obj.close();
 }
}
var dbPool = new objectPool(poolOption); //创建对象池
dbPool.manager(); //开始对象池维护
process.on('exit', function(){
 dbPool.destroy(); //程序退出,销毁对象池
});
function DBConnection(){
 this.open = function(){
 if(!this.db) {
 this.db = dbPool.getOne();
 }
 return this;
 };
 this.close = function(){
 if(this.db) {
 dbPool.freeOne(this.db);
 this.db = null;
 }
 };
};
exports.DBConnection = DBConnection;
var dbConnection = new DBConnection().open();
dbConnection.db.collection('category').find({}, function(err, cs){
 dbConnection.close(); //这里你可以不写,超过最大工作时间后资源会自动归入空闲队列
 //TODO
});
7 回复

光写前端对对象池概念真是好陌生, 这是为了数据库性能做的模块么?

嗯,是的,主要是减少重复连接数据库的开销,不知道Mongo的连接开销是多少,但是建立连接肯定是有开销的,

@saber Node 使用数据库的时候 Mongo 是经常断开是么? 以前写玩具时候我都直接连接一次用到底的, 这么说方法不对

@jiyinyiyong 如果你的操作是顺序的,那没问题, 但正常情况,特别是web应用,操作基本上是并发的, 如果你的连接数跟不上并发数,那么会造成操作阻塞, 新来的操作必须等同一连接上的操作结束后才能继续

@saber 原来还要考虑并发的情况. 学习了

这种方式真的不推荐使用,连接池还是由驱动保持吧

回到顶部

AltStyle によって変換されたページ (->オリジナル) /