C#實現Thrift串連池[新]

來源:互聯網
上載者:User

2012-10-08更新內容

1,因為對象池採用的是Stack,並且沒有“對象在使用中,但仍在池中”這種情況,都是直接pop出來的,所以就廢棄掉了idle狀態,但是加入了“工作對象數量”的概念。

2,順便把Stack改成了安全執行緒的ConcurrentStack,但這不是很重要,因為lock還是保留了下來

3,一些不需要lock的地方都去掉了

4,歸還對象時把串連關閉了(但不銷毀,第一版串連沒關閉,總是出問題),這就使得ValidateOnBorrow一定要置為true了

5,樣本中的process方法把Service對象用using包了起來,以及時釋放串連

原文:

項目決定採用Thrift,所有測試通過後,那就要解決串連池的問題了,網上一通海搜,難道是我用的關鍵詞不對?居然沒有C#對Thrift串連池的實現,沒辦法,只有根據對象池的模式自己寫一個,經過多人多線程測試後,基本沒有問題了,比較粗糙,歡迎拍磚

幾個原則:

1,能控制對象池中對象的總數

2,能控制對象池中空閑對象的總數(改為控制工作對象的總數)

3,提供一個借出對象的介面

4,提供一個歸還對象的介面

5,借出和歸還的對象有檢驗機制

這樣,大致就可以用了,未來可以加上逾時自動釋放的機制,目前未實現。

分如下幾部分

1:設定檔/設定物件

設定檔肯定要有,設定物件僅僅是為了操作方便(比如別的地方要用),如果沒有特殊的需求,直接把配置項寫到私人屬性裡就可以了

public class ThriftConfig{/// <summary>/// 伺服器位址/// </summary>public string Host { get; set; }/// <summary>/// 服務連接埠/// </summary>public int Port { get; set; }/// <summary>/// 傳輸編碼/// </summary>public Encoding Encode { get; set; }/// <summary>/// 是否啟用壓縮/// </summary>public bool Zipped { get; set; }/// <summary>/// 連線逾時/// </summary>public int Timeout { get; set; }/// <summary>/// 可以從緩衝池中指派至的最大數量/// </summary>public int MaxActive { get; set; }/// <summary>/// 緩衝池中最大空閑對象數量/// </summary>public int MaxIdle { get; set; }/// <summary>/// 緩衝池中最小空閑對象數量/// </summary>public int MinIdle { get; set; }/// <summary>/// 阻塞的最大數量/// </summary>public int MaxWait { get; set; }/// <summary>/// 從緩衝池中指派至時是否驗證對象/// </summary>public bool ValidateOnBorrow { get; set; }/// <summary>/// 從緩衝池中歸還對象時是否驗證對象/// </summary>public bool ValidateOnReturn { get; set; }/// <summary>/// 從緩衝池中掛起對象時是否驗證對象/// </summary>public bool ValidateWhiledIdle { get; set; }

設定檔不過就是上述內容的xml形式,不贅述

2,串連池類

public class ThriftPool{#region 屬性private ThriftConfig config;/// <summary>/// 對象緩衝池/// </summary>//private static Stack<TTransport> objectPool { get; set; }private static ConcurrentStack<TTransport> objectPool { get; set; }/// <summary>/// 同步對象/// </summary>private static AutoResetEvent resetEvent;/// <summary>/// 每取走一例,表示啟用物件加1,此屬性可控制對象池容量/// </summary>private static volatile int activedCount = 0;/// <summary>/// 同步對象鎖/// </summary>private static object locker = new object();#endregion#region 建構函式public ThriftPool(){config = GetConfig();CreateResetEvent();CreateThriftPool();}#endregion#region 公有方法/// <summary>/// 從對象池取出一個對象/// </summary>/// <returns></returns>public TTransport BorrowInstance(){lock (locker){//Console.WriteLine("借前對象池個數:{0},工作對象個數:{1}", objectPool.Count(), activedCount);TTransport transport;//對象池無空閑對象if (objectPool.Count() == 0){//對象池已啟用物件數達上限if (activedCount == config.MaxActive){resetEvent.WaitOne();}else{PushObject(CreateInstance());}}if (!objectPool.TryPop(out transport)) throw new Exception("串連池異常");//transport = objectPool.Pop();activedCount++;//檢查對象池存量//對象池存量小於最小空閑數,並且啟用數小於最大啟用數,添加一個對象到對象池if (objectPool.Count() < config.MinIdle && activedCount < config.MaxActive){PushObject(CreateInstance());}if (config.ValidateOnBorrow){ValidateOnBorrow(transport);}return transport;}}/// <summary>/// 歸還一個對象/// </summary>/// <param name="instance"></param>public void ReturnInstance(TTransport instance){//對象池容量達到上限,不再返回線程池,直接銷毀if (objectPool.Count() == config.MaxIdle){DestoryInstance(instance);}else{if (config.ValidateOnReturn){ValidateOnReturn(instance);}PushObject(instance);activedCount--;//發通知訊號,有對象歸還到對象池resetEvent.Set();}//Console.WriteLine("歸還後對象池個數:{0},歸還後工作對象個數:{1}", objectPool.Count(), activedCount);}#endregion#region 私人方法/// <summary>/// 建立線程同步對象/// </summary>private void CreateResetEvent(){if (resetEvent == null){resetEvent = new AutoResetEvent(false);}}/// <summary>/// 建立對象池/// </summary>private void CreateThriftPool(){if (objectPool == null){objectPool = new ConcurrentStack<TTransport>();// new Stack<TTransport>();}}/// <summary>/// 添加對象到對象池/// </summary>/// <param name="transport"></param>private void PushObject(TTransport transport){objectPool.Push(transport);}/// <summary>/// 建立一個對象/// </summary>/// <returns></returns>private TTransport CreateInstance(){TTransport transport = new TSocket(config.Host, config.Port);transport.Open();return transport;}/// <summary>/// 取出對象時校正對象/// </summary>private void ValidateOnBorrow(TTransport instance){if (!instance.IsOpen){instance.Open();}}/// <summary>/// 歸還對象時校正對象/// </summary>private void ValidateOnReturn(TTransport instance){if (instance.IsOpen){instance.Close();}}/// <summary>/// 銷毀對象/// </summary>/// <param name="instance"></param>private void DestoryInstance(TTransport instance){instance.Flush();if (instance.IsOpen){instance.Close();}instance.Dispose();}/// <summary>/// 得到配置參數/// </summary>/// <returns></returns>private ThriftConfig GetConfig(){return Utility.GetConfig();}#endregion}

封裝了一個服務類來取Thrift連線物件,把對象池模式隱藏起來

要注意的是,這個對象必須實現IDisposable介面,因為要手動在串連完畢後歸還對象

    internal class Service : IDisposable    {        ThriftPool pool;        TTransport transport;        MyThriftTest.Client client;//我寫的測試伺服器就叫MyThriftTest        bool disposed;        public ThriftConfig config { get; set; }        public Service()        {            disposed = false;            pool = new ThriftPool();            transport = pool.BorrowInstance();//從對象池取出一個對象            TProtocol protocol = new TBinaryProtocol(transport);            client = new MyThriftTest.Client(protocol);        }        public string Invoke(string arg1, string arg2)        {//我寫的測試方法就叫invoke            return client.invoke(arg1, arg2);        }        ~Service()        {            Dispose(false);        }        protected void Dispose(bool disposing)        {            if (!disposed)            {                if (disposing)                {                    pool.ReturnInstance(transport);//歸還當前對象到對象池                }                // Release unmanaged resources                disposed = true;            }        }        public void Dispose()        {            Dispose(true);            GC.SuppressFinalize(this);        }    }

測試:

static void Main(string[] args){for (int i = 0; i < 1000; i++){Thread t = new Thread(new ThreadStart(process));t.Name = "thread:" + i;t.Start();}}private static void process(){try{using(Service svr=new Service()){string o = svr.Invoke("hello", "world");log(o);}}catch (Exception ex){log(ex);}}static object o = new object();private static void log(string msg){lock (o){using (StreamWriter sm = new StreamWriter(@"D:\thrift.txt", true)){sm.WriteLine(msg);}}}

測試代碼中寫檔案而不是輸出到控制台,主要是因為控制台可顯示的條目過少,一旦出了錯就滾過去了

測試良好,有發現的問題再改吧,再次聲明,歡迎拍磚

參考連結:

C# http://www.cnblogs.com/RushSykes/archive/2012/04/16/2451880.html 

Javahttp://www.cnblogs.com/51cto/archive/2010/08/18/Thrift_Connection_pool.html

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.