`
pcajax
  • 浏览: 2183653 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

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

分享到:
评论

相关推荐

    C#的对象池课件

    - 课件中的"对象池管理.doc"文档可能包含详细的理论介绍和代码示例,帮助深入理解对象池的工作原理和实现方式。 - "对象池.txt"文件可能是补充材料,例如最佳实践或常见问题解答。 通过学习C#的对象池,开发者...

    C# ajax和数据库连接池小实例

    下面将详细探讨C#、Ajax以及数据库连接池的相关知识点。 一、C#与Ajax的结合使用 1. C# Web应用基础:C#通常与ASP.NET框架一起使用,构建服务器端的Web应用。通过编写C#代码,开发者可以处理HTTP请求,生成动态...

    Visual C#.NET数据库开发经典案例解析》的配套光盘

    《Visual C#.NET数据库开发经典案例解析》是一本专注于C#编程语言与数据库结合应用的实战书籍,其配套光盘提供了多个实际管理系统的源代码,包括进销存、人力资源、生产、财务、图书、酒店、医院和教务等多个领域的...

    C#开发的蜘蛛爬虫程序

    C#是一种由微软公司推出的面向对象的编程语言,广泛应用于Windows平台上的各种应用程序开发,包括网络爬虫。爬虫,也称为网络蜘蛛或网页抓取器,是一种自动浏览互联网并提取网页数据的程序。在C#中开发爬虫,可以...

    C# http post协议,数据交互形式为json

    这个库提供了解析JSON字符串、序列化对象到JSON、反序列化JSON到对象等操作,使得JSON与C#对象之间的转换变得简单。 3. **POST请求的构建**:使用`HttpClient`发送POST请求时,需要创建一个`HttpRequestMessage`...

    HtmlDom解析组件(C#)

    6. **性能优化**:虽然HTML解析可能涉及到大量的内存分配,但HtmlAgilityPack通过内存池和缓存策略优化了性能,减少内存消耗。 以下是一些使用HtmlAgilityPack的示例代码片段: ```csharp using HtmlAgilityPack; ...

    C#数据库开发经典案例解析光盘源码

    下面,我们将详细探讨C#数据库开发的一些核心知识点。 首先,C#语言与数据库的连接是通过ADO.NET(微软提供的数据访问技术)实现的。ADO.NET提供了诸如SqlConnection、SqlCommand、SqlDataReader等类,用于创建、...

    C#操作IIS完整解析

    ### C#操作IIS完整解析 #### 一、版本问题 在进行编程操作IIS之前,首先要考虑的一个关键问题是IIS的版本。不同版本的IIS对于编程方式有着不同的要求和影响。例如,在IIS 6.0时代,通常会使用`System.Directory...

    最简单的C#线程池创建Demo演示代码

    本文将详细解析如何在C#中创建并使用线程池,通过一个简单的Demo演示来阐述相关知识点。 线程池是操作系统提供的一种资源管理方式,它维护着一组可重用的线程,当需要执行新的任务时,线程池会从已有的线程中分配,...

    Visual C#.NET数据库开发经典案例解析(代码)

    《Visual C#.NET数据库开发经典案例解析》这本书深入探讨了使用C#.NET进行数据库开发的各种技术和实践。书中通过丰富的案例,详细介绍了如何利用.NET Framework和C#语言的强大功能来构建高效、稳定的数据库应用系统...

    SuperSocket Socket C# 通讯详细介绍

    2. **Session**: 代表一个客户端的连接,每个客户端连接都会创建一个对应的Session对象。Session提供了数据收发、状态管理和生命周期管理的功能。 3. **Protocol**: 协议处理模块,允许开发者定义自己的通信协议。...

    23个设计模式C#代码

    本资源包含23种经典的设计模式的C#实现,以下是对这些模式的详细说明: 1. 单例模式(Singleton):确保一个类只有一个实例,并提供全局访问点。在C#中,通常使用静态成员和私有构造函数来实现。 2. 工厂模式...

    C#飞机大战源码

    源码中可能还包括一些特定的优化技巧,例如对象池设计以减少频繁创建和销毁对象带来的性能开销,或者使用多线程技术来提高游戏的流畅性。 总的来说,C#飞机大战源码是一个学习C#编程和游戏开发的理想教材。通过深入...

    最完全的基于C#的网络爬虫

    - C#:C#是Microsoft开发的一种面向对象的编程语言,广泛应用于桌面应用、游戏开发以及Web服务等。 2. **C#中的网络请求**: - 使用`System.Net.Http`命名空间中的HttpClient类,可以方便地发送HTTP请求,获取...

    Visual C#.NET数据库开发经典案例解析源码

    《Visual C#.NET数据库开发经典案例解析源码》是一份专为C#.NET开发者准备的珍贵资源,旨在通过具体的案例帮助读者深入理解如何利用C#.NET进行数据库开发。这个压缩包包含了多个示例项目的源代码,是学习和提升C#...

    C#优化157个实例含源代码含文档

    1. 内存管理:探讨如何合理使用堆和栈,避免内存泄漏,以及何时使用对象池来复用对象以减少GC压力。 2. 循环优化:分析for、foreach、while等循环结构的性能差异,以及如何通过并行处理、异步操作来提升循环效率。 3...

    Visual C#.NET数据库开发经典案例解析(代码).rar

    《Visual C#.NET数据库开发经典案例解析》是一本专注于C#编程语言与数据库结合应用的实战教程。通过这本书,开发者可以深入理解如何在C#.NET环境下进行高效且可靠的数据库开发。压缩包中的文件包含了各个章节的源...

    oracle+c#实例

    ODP.NET提供了ADO.NET接口,包括DataSet、DataTable、DataAdapter等对象,使得在C#中处理Oracle数据如同操作本地数据一样方便。 1. 连接Oracle:使用OracleConnection类建立与Oracle服务器的连接,通过...

    Head First 设计模式 C#版的源码

    C#中通常通过共享对象池来实现。 10. **桥接模式**(Bridge):将抽象部分与它的实现部分分离,使它们都可以独立地变化。在C#中,可以使用接口和多层继承来实现。 11. **组合模式**(Composite):允许你将对象...

    基于C# 的网络爬虫源程序

    在编程世界中,C#是一种强大的、面向对象的语言,常用于开发Windows桌面应用、游戏以及服务器端软件。这个“基于C#的网络爬虫源程序”就是利用C#的强大功能来构建一个能够遍历网页、抓取数据的工具。 **C#基础知识*...

Global site tag (gtag.js) - Google Analytics