Python Implementation of the Object Pool Design Pattern
It seems to me, from your description, that what you need is a pool of connections, not of objects. For simple thread-safety, just keep the reusable connections in a Queue.Queue
instance, call it pool
. When a thread instantiates a connection-wrapping object, the object gets its connection via pool.get()
(which automaticaly enqueues it to wait if there are no connections currently availabe and dequeues it when a connection's ready for it); when the object's done using its connection, it puts it back in the pool via pool.put
.
There's so little universally-required, general-purpose functionality in this, beyond what Queue.Queue
already gives you, that it's not surprising no module providing it is well known or popular -- hard to make a module widespread when it has about 6 lines of functional code in all (e.g. to call a user-supplied connection factory to populate the queue either in advance or just-in-time up to some maximum number -- not a big added value generally, anyway). "Thick glue", thickly wrapping the underlying functionality from a standard library module without substantial added value, is an architectural minus, after all;-).
I had a similar problem and I must say Queue.Queue is quite good, however there is a missing piece of the puzzle. The following class helps deal with ensuring the object taken gets returned to the pool. Example is included.
I've allowed 2 ways to use this class, with keyword or encapsulating object with destructor. The with keyword is preferred but if you can't / don't want to use it for some reason (most common is the need for multiple objects from multiple queues) at least you have an option. Standard disclaimers about destructor not being called apply if you choose to use that method.
Hopes this helps someone with the same problem as the OP and myself.
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
'''