2009-10-03 133 views
19

實現我需要一個Object Pool,而非執行它自己,我想我會到處尋找現成的和測試Python庫。Python的對象池設計模式

我發現什麼其他很多人looking,但沒有得到許多直接的答案,所以我把它在這裏堆棧溢出。

在我的情況下,我有大量的線程(使用threading模塊),它需要偶爾調用遠程的基於SOAP的服務器。他們每個人都可以建立自己的連接到服務器,但是設置一個套接字並完成身份驗證過程很昂貴(它受服務器限制),所以我想共享一個連接池,只根據需要創建更多連接。

如果項目池是工人的子過程,我可能選擇multiprocessing.pool,但事實並非如此。如果他們是工作線程,我可能選擇了this implementation,但它們不是。

如果他們是MySQL連接,我可能選擇pysqlpool,但事實並非如此。同樣,SQLAlchemy Pool已經結束。

如果有一個線程,使用可變數量的連接/對象,我會考慮this implementation,但我需要它是線程安全的。

我知道我可以很快再次實現這一點,但由於有很多人在尋找它,我想對堆棧溢出的規範答案就好了。

回答

23

在我看來,從你的描述來看,你需要的是一個連接池,而不是對象。爲了簡單的線程安全,只需將可重用連接保存在Queue.Queue實例中,請將其稱爲pool。當一個線程實例化一個連接包裝對象時,該對象通過pool.get()獲得連接(如果當前沒有可用的連接並在連接準備就緒時將其自動排隊,則該對象自動排隊等待)。當對象使用其連接完成時,它通過pool.put將其放回池中。

在這方面,除了Queue.Queue已經給你的東西之外,還有這麼少的普遍需求的通用功能,它並不令人驚訝,沒有提供它的模塊是衆所周知的或流行的 - 很難在模塊廣泛使用總共有6行功能代碼(例如,調用用戶提供的連接工廠來預先填充隊列,或者實時填充某個最大數量 - 總體上不是一個很大的附加值)。 「厚厚的膠水」,從標準庫模塊中厚厚地包裝底層功能,沒有顯着的附加價值,畢竟是一種架構減去;-)。

+0

啊,沒錯,等着,如果池中沒有東西了,那就是列表所缺乏的。我以爲我很聰明,而不是隊列,但實際上太聰明瞭。 :) – 2009-10-03 19:22:39

+0

@Lennart,也沒有_guarantee_的線程安全性,你可能會或可能不會遇到問題取決於實現 - 與Queue.Queue,你的線程安全性是有保證的。 – 2009-10-04 01:14:47

+0

Python有一個線程安全的隊列已經內置?我不知道!是的,這會加快實現(我認爲這會很短,但主要是考慮併發問題)。對不起,我不瞭解你對「連接池」與「對象池」的區別。我說我想「分享連接池」,但每個連接都包含在一個對象中,所以它確實也是一個對象池。然而,我試圖做的區別在於連接對象不是活動的(與multiprocessing.pool不同)。 – Oddthinking 2009-10-05 01:42:21

4

我有一個類似的問題,我必須說Queue.Queue是相當不錯的,但是有一個缺失的難題。以下課程幫助處理確保所採取的對象返回到池中。包含示例。

我已經允許2種方式使用這個類,關鍵字或封裝析構函數的對象。 with關鍵字是首選,但如果由於某種原因無法/不想使用它(最常見的情況是需要多個隊列中的多個對象),則至少您有一個選項。如果您選擇使用該方法,則關於析構函數未被調用的標準免責聲明適用。

希望這可以幫助與OP和我自己相同問題的人。

class qObj(): 
    _q = None 
    o = None 

    def __init__(self, dQ, autoGet = False): 
     self._q = dQ 

     if autoGet == True: 
      self.o = self._q.get() 

    def __enter__(self): 
     if self.o == None: 
      self.o = self._q.get() 
      return self.o 
     else: 
      return self.o 

    def __exit__(self, type, value, traceback): 
     if self.o != None: 
      self._q.put(self.o) 
      self.o = None 

    def __del__(self): 
     if self.o != None: 
      self._q.put(self.o) 
      self.o = None 


if __name__ == "__main__": 
    import Queue 

    def testObj(Q): 
     someObj = qObj(Q, True) 

     print 'Inside func: {0}'.format(someObj.o) 

    aQ = Queue.Queue() 

    aQ.put("yam") 

    with qObj(aQ) as obj: 
     print "Inside with: {0}".format(obj) 

    print 'Outside with: {0}'.format(aQ.get()) 

    aQ.put("sam") 

    testObj(aQ) 

    print 'Outside func: {0}'.format(aQ.get()) 

    ''' 
    Expected Output: 
    Inside with: yam 
    Outside with: yam 
    Inside func: sam 
    Outside func: sam 
    ''' 
+0

缺少恕我直言的唯一一件事是'__getattr__'方法,因此您可以將其視爲封裝對象的包裝 – ThatAintWorking 2014-06-26 18:29:13