2009-10-03 12 views
19

私はObject Poolが必要です。それを自分で実装するのではなく、既成のテスト済みのPythonライブラリを見回すと思いました。オブジェクトプールデザインパターンのPython実装

私が見つけたのは他の多くの人々lookingでしたが、多くのストレートな回答が得られなかったので、ここでスタックオーバーフローを起こしました。

私の場合、リモートSOAPベースのサーバーを時折呼び出す必要があるスレッドが多数あります(threadingモジュールを使用しています)。彼らはそれぞれサーバーに独自の接続を確立することができますが、ソケットの設定と認証プロセスの完了はコストがかかります(サーバーによって抑制される)ので、必要に応じてさらに多くの接続を共有したいと考えています。

プールするアイテムがワーカーサブプロセスの場合は、multiprocessing.poolを選択した可能性がありますが、そうではありません。彼らがワーカースレッドであれば、私はthis implementationを選択しているかもしれませんが、そうではありません。

MySQL接続の場合はpysqlpoolを選択した可能性がありますが、そうではありません。同様にSQLAlchemy Poolが出ています。

可変数の接続/オブジェクトを使用するスレッドが1つあった場合、私はthis implementationと考えていますが、スレッドセーフである必要があります。

私はこれをかなり迅速に実装することができると知っていますが、探している人が多いことを考えれば、スタックオーバーフローに関する標準的な答えがいいと思っていました。

答えて

23

あなたの必要なものは、接続のプールであり、オブジェクトではないようです。単純なスレッドセーフであれば、再利用可能な接続をQueue.Queueインスタンスに保持するだけです。poolと呼んでください。スレッドが接続ラッピングオブジェクトをインスタンス化するとき、オブジェクトはpool.get()(現在利用可能な接続がない場合は自動的に待ち行列にエンキューし、接続の準備ができたらデキューする)によって接続を取得します。オブジェクトが接続を使用して完了すると、オブジェクトはpool.put経由でプールに戻されます。

Queue.Queueがすでにあなたに与えていることを超えて、普遍的な機能を持つ汎用機能はほとんどありません。モジュールが提供されていることは驚くことではありませんが、モジュールが普及するのは難しい6行の機能コードすべて(例えば、ユーザー提供の接続ファクトリを呼び出して、あらかじめまたは最大時間にジャストインタイムのいずれかでキューにデータを格納します。実質的な付加価値なしに標準ライブラリモジュールから基本的な機能を太く包み込む「厚い接着剤」は、結局のところ建築的なマイナスです。

+0

ああ、プールに何も残っていなければ、リストが欠けているのです。私はキューの代わりにリストで賢いと思ったけど、実際にはあまりにも巧妙だった。 :) –

+0

@Lennart、スレッド安全性の保証もなく、実装によっては問題が発生する場合もあります。Queue.Queueを使用すると、スレッドの安全性が保証されます。 –

+0

Pythonにはスレッドセーフなキューが既に組み込まれていますか?私はそれを知らなかった!はい、それは実装をスピードアップします(私は短いと思っていましたが、主に並行性の問題を考えて費やしました)。申し訳ありませんが、私は "プールのプール"対 "オブジェクトのプール"の違いを理解していませんでした。私は「接続のプールを共有したい」と言ったが、それらの接続のそれぞれはオブジェクト内にラップされているので、実際にはオブジェクトのプールでもある。しかし、私が作成しようとしていたのは、接続オブジェクトがアクティブではないということです(マルチプロセッシングプールと違い) – Oddthinking

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

IMHOが唯一欠けているのは '__getattr__'メソッドなので、これをカプセル化されたオブジェクトのラッパーとして扱うことができます – ThatAintWorking