C#對象池詳細解析

來源:互聯網
上載者:User

在系統設計中,經常會使用“池”的概念。比如資料庫連接池,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

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.