c#对象池详解

在系统设计中,经常会使用“池”的概念。比如数据库连接池,socket连接池,线程池,组件队列。“池”可以节省对象重复创建和初始化所耗费 的时间,可以简化对象获取和使用的过程。对于那些被系统频繁请求和使用的对象,如果使用这种机制,可以使系统性能得到很大提高。特别象数据库连接这种对 象,客户端与数据库服务器端建立连接时,是比较慢的,如果每次进行数据库操作,都要先进行数据库连接,系统效率将非常低下。 powered by 25175.net

“池”的概念就是将被使用的对象事先创建好,保存在列表中,供客户端取用。当客户端取得一个对象时,这个对象就已经是按照特定上下文环境初始化好,马上即 可使用的了。当客户端使用完毕,需要将对象归还给“池”,最后,在系统生命期结束时,由“池”统一释放这些对象。从另一个概念上来说,这也是一种“以空间 换时间”的做法,我们在内存中保存一系列整装待命的对象,供人随时差遣。与系统效率相比,这些对象所占用的内存空间太微不足道了。

“池”的结构是通用的,就是不管他里面保存的是哪一种对象,他的工作方法都基本不变。无非是初始化一系列对象,然后提供一个获取可用对象,一个归还对象的接口。

基于这种考虑,我们可以建立一个通用的对象池,只要某些对象符合“一些基本要求”(这个基本要求,可以使用Interface模式来限定),就可以使用通用对象池来存取和管理。

创建一个接口,用于限定对象池中所保存的对象的基本行为:

复制C#代码保存代码public interface IDynamicObject 

    void Create(Object param); 
    Object GetInnerObject(); 
    bool IsValidate(); 
    void Release(); 
}

我们在对象池中存放的对象,必须继承上面的接口,并实现接口定义的每一个方法。

Create方法中,用户可以用来创建实际的对象,如建立数据库连接,并打开这个连接;GetInnerObject方法,使用户可以返回这个实际 的对象,如一个SqlConnection对象;IsValidate方法是用来判断用户自定义对象的有效性的,是对象池决定是否重新创建对象的标志; Release方法中,用户可以进行资源释放工作。

有了上面的接口定义,为我们可以在列表中保存用户自定义对象打下了基础。下面就是要实现这个ObjectPool了。

用户自定义对象在我们的ObjectPool中,可以用列表存储,如ArrayList或者Hashtable,为了表示每个用户对象的状态,我们 还需要将用户自定义对象包装一下,然后在放到列表中保存。下面定义了一个ObjectPool类的子类,用于包装用户自定义对象:

复制C#代码保存代码private class PoolItem 

    private IDynamicObject _object; 
    private bool _bUsing; 
    private Type _type; 
    private Object _CreateParam;

    public PoolItem(Type type, Object param) 
    { 
        _type = type; 
        _CreateParam = param; 
        Create(); 
    }

    private void Create() 
    { 
        _bUsing = false; 
        _object = (IDynamicObject) System.Activator.CreateInstance(_type); 
        _object.Create(_CreateParam); 
    }

    public void Recreate() 
    { 
        _object.Release(); 
        Create(); 
    }

    public void Release() 
    { 
        _object.Release(); 
    }

    public Object InnerObject 
    { 
        get { return _object.GetInnerObject(); } 
    }

    public int InnerObjectHashcode 
    { 
        get { return InnerObject.GetHashCode(); } 
    }

    public bool IsValidate 
    { 
        get { return _object.IsValidate(); } 
    }

    public bool Using 
    { 
        get { return _bUsing; } 
        set { _bUsing = value; } 
    } 
}// class PoolItem

 

这个类,一个关键的属性是Using,该属性表示对象是否正在被被用户使用。注意,PoolItem创建时,接受一个Object类型的Param参 数,这个参数最后被传递给用户自定义对象的Create方法。用户可以利用这一点,在创建ObjectPool时指定一些参数,供其自定义对象在创建时使 用。比如创建SocketPool时,将服务器IP,端口通过Param传递给自定义对象的Create方法,用户就可以在Create方法中连接指定的 服务器了。powered by 25175.net

以下是ObjectPool的具体实现代码:

复制C#代码保存代码public sealed class ObjectPool 

    private Int32 _nCapacity; 
    private Int32 _nCurrentSize; 
    private Hashtable _listObjects; 
    private ArrayList _listFreeIndex; 
    private ArrayList _listUsingIndex; 
    private Type _typeObject; 
    private Object _objCreateParam;

    public ObjectPool(Type type, Object create_param, Int32 init_size, Int32 capacity) 
    { 
        if (init_size < 0 || capacity < 1 || init_size > capacity) 
        { 
            throw (new Exception("Invalid parameter!")); 
        }

        _nCapacity = capacity; 
        _listObjects = new Hashtable(capacity); 
        _listFreeIndex = new ArrayList(capacity); 
        _listUsingIndex = new ArrayList(capacity); 
        _typeObject = type; 
        _objCreateParam = create_param;

        for (int i = 0; i < init_size; i++) 
        { 
            PoolItem pitem = new PoolItem(type, create_param); 
            _listObjects.Add(pitem.InnerObjectHashcode, pitem); 
            _listFreeIndex.Add(pitem.InnerObjectHashcode); 
        }

        _nCurrentSize = _listObjects.Count; 
    }

    public void Release() 
    { 
        lock (this) 
        { 
            foreach (DictionaryEntry de in _listObjects) 
            { 
                ((PoolItem) de.Value).Release(); 
            } 
            _listObjects.Clear(); 
            _listFreeIndex.Clear(); 
            _listUsingIndex.Clear(); 
        } 
    }

    public Int32 CurrentSize 
    { 
        get { return _nCurrentSize; } 
    }

    public Int32 ActiveCount 
    { 
        get { return _listUsingIndex.Count; } 
    }

    public Object GetOne() 
    { 
        lock (this) 
        { 
            if (_listFreeIndex.Count == 0) 
            { 
                if (_nCurrentSize == _nCapacity) 
                { 
                    return null; 
                } 
                PoolItem pnewitem = new PoolItem(_typeObject, _objCreateParam); 
                _listObjects.Add(pnewitem.InnerObjectHashcode, pnewitem); 
                _listFreeIndex.Add(pnewitem.InnerObjectHashcode); 
                _nCurrentSize++; 
            }

            Int32 nFreeIndex = (Int32) _listFreeIndex[0]; 
            PoolItem pitem = (PoolItem) _listObjects[nFreeIndex]; 
            _listFreeIndex.RemoveAt(0); 
            _listUsingIndex.Add(nFreeIndex);

            if (!pitem.IsValidate) 
            { 
                pitem.Recreate(); 
            }

            pitem.Using = true; 
            return pitem.InnerObject; 
        } 
    }

    public void FreeObject(Object obj) 
    { 
        lock (this) 
        { 
            int key = obj.GetHashCode(); 
            if (_listObjects.ContainsKey(key)) 
            { 
                PoolItem item = (PoolItem) _listObjects[key]; 
                item.Using = false; 
                _listUsingIndex.Remove(key); 
                _listFreeIndex.Add(key); 
            } 
        } 
    }

    public Int32 DecreaseSize(Int32 size) 
    { 
        Int32 nDecrease = size; 
        lock (this) 
        { 
            if (nDecrease <= 0) 
            { 
                return 0; 
            } 
            if (nDecrease > _listFreeIndex.Count) 
            { 
                nDecrease = _listFreeIndex.Count; 
            }

            for (int i = 0; i < nDecrease; i++) 
            { 
                _listObjects.Remove(_listFreeIndex[i]); 
            }

            _listFreeIndex.Clear(); 
            _listUsingIndex.Clear();

            foreach (DictionaryEntry de in _listObjects) 
            { 
                PoolItem pitem = (PoolItem) de.Value; 
                if (pitem.Using) 
                { 
                    _listUsingIndex.Add(pitem.InnerObjectHashcode); 
                } 
                else 
                { 
                    _listFreeIndex.Add(pitem.InnerObjectHashcode); 
                } 
            } 
        } 
        _nCurrentSize -= nDecrease; 
        return nDecrease; 
    } 
}

虽然.net对数据库连接已经提供了连接池,但是,经测试,使用上述通用对象池实现的数据库连接池,效率要比直接使用.net管理的连接池高。因为他减少了Open和Close操作,从而节省了时间。

代码如下:

复制C#代码保存代码public class DBPool 

    private class SqlConnectionObject : IDynamicObject 
    { 
        private SqlConnection _SqlConn;

        public SqlConnectionObject() 
        { 
            _SqlConn = null; 
        }

        #region IDynamicObject Members

        public void Create(Object param) 
        { 
            String strConn = (String) param; 
            _SqlConn = new SqlConnection(strConn); 
            _SqlConn.Open(); 
        }

        public Object GetInnerObject() 
        { 
            // TODO: Add SqlConnectionObject.GetInnerObject implementation 
            return _SqlConn; 
        }

        public bool IsValidate() 
        { 
            return (_SqlConn != null 
                && _SqlConn.GetHashCode() > 0 
                && _SqlConn.State == ConnectionState.Open); 
        }

        public void Release() 
        { 
            // TODO: Add SqlConnectionObject.Release implementation 
            _SqlConn.Close(); 
        }

        #endregion 
    }

    private ObjectPool _Connections;

    public DBPool(string connection, int initcount, int capacity) 
    { 
        if (connection == null || connection == "" || initcount < 0 || capacity < 1) 
        { 
            throw (new Exception("Invalid parameter!")); 
        } 
        _Connections = new ObjectPool(typeof(SqlConnectionObject), connection, initcount, capacity); 
    }

    public SqlConnection GetConnection() 
    { 
        return (SqlConnection) _Connections.GetOne(); 
    }

    public void FreeConnection(SqlConnection sqlConn) 
    { 
        _Connections.FreeObject(sqlConn); 
    }

    public void Release() 
    { 
        _Connections.Release(); 
    }

    public int Count 
    { 
        get { return _Connections.CurrentSize; } 
    }

    public int UsingCount 
    { 
        get { return _Connections.ActiveCount; } 
    }

    public int DecreaseSize(int size) 
    { 
        return _Connections.DecreaseSize(size); 
    } 
} // DBPool

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值