Add pooling helpers.
This commit is contained in:
parent
bc40569572
commit
f203dd1c02
80
pylibmc.py
80
pylibmc.py
@ -112,6 +112,86 @@ class Client(_pylibmc.client):
|
|||||||
|
|
||||||
behaviors = property(get_behaviors, set_behaviors)
|
behaviors = property(get_behaviors, set_behaviors)
|
||||||
|
|
||||||
|
from contextlib import contextmanager
|
||||||
|
|
||||||
|
class ClientPool(list):
|
||||||
|
"""Client pooling helper.
|
||||||
|
|
||||||
|
This is mostly useful in threaded environments, because a client isn't
|
||||||
|
thread-safe at all. Instead, what you want to do is have each thread use
|
||||||
|
its own client, but you don't want to reconnect these all the time.
|
||||||
|
|
||||||
|
The solution is a pool, and this class is a helper for that.
|
||||||
|
|
||||||
|
>>> mc = Client(["127.0.0.1"])
|
||||||
|
>>> pool = ClientPool()
|
||||||
|
>>> pool.fill(mc, 4)
|
||||||
|
>>> with pool.reserve() as mc:
|
||||||
|
... mc.set("hi", "ho")
|
||||||
|
... mc.delete("hi")
|
||||||
|
...
|
||||||
|
"""
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def reserve(self):
|
||||||
|
"""Reserve a client, and put it back into the pool when done."""
|
||||||
|
mc = self.pop()
|
||||||
|
try:
|
||||||
|
yield mc
|
||||||
|
finally:
|
||||||
|
self.append(mc)
|
||||||
|
|
||||||
|
def fill(self, mc, n_slots):
|
||||||
|
"""Fill *n_slots* of the pool with clones of *mc*."""
|
||||||
|
for i in xrange(n_slots):
|
||||||
|
self.append(mc.clone())
|
||||||
|
|
||||||
|
class ThreadMappedPool(dict):
|
||||||
|
"""Much like the *ClientPool*, helps you with pooling.
|
||||||
|
|
||||||
|
In a threaded environment, you'd most likely want to have a client per
|
||||||
|
thread. And there'd be no harm in one thread keeping the same client at all
|
||||||
|
times. So, why not map threads to clients? That's what this class does.
|
||||||
|
|
||||||
|
If a client is reserved, this class checks for a key based on the current
|
||||||
|
thread, and if none exists, clones the master client and inserts that key.
|
||||||
|
|
||||||
|
>>> mc = Client(["127.0.0.1"])
|
||||||
|
>>> pool = ThreadMappedPool(mc)
|
||||||
|
>>> with pool.reserve() as mc:
|
||||||
|
... mc.set("hi", "ho")
|
||||||
|
... mc.delete("hi")
|
||||||
|
...
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __new__(cls, master):
|
||||||
|
return super(ThreadMappedPool, cls).__new__(cls)
|
||||||
|
|
||||||
|
def __init__(self, master):
|
||||||
|
self.master = master
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def reserve(self):
|
||||||
|
"""Reserve a client.
|
||||||
|
|
||||||
|
Creates a new client based on the master client if none exists for the
|
||||||
|
current thread.
|
||||||
|
"""
|
||||||
|
key = threading.current_thread().name
|
||||||
|
mc = self.pop(key, None)
|
||||||
|
if mc is None:
|
||||||
|
mc = self.master.clone()
|
||||||
|
try:
|
||||||
|
yield mc
|
||||||
|
finally:
|
||||||
|
self[key] = mc
|
||||||
|
|
||||||
|
# This makes sure ThreadMappedPool doesn't exist with non-thread Pythons.
|
||||||
|
try:
|
||||||
|
import threading
|
||||||
|
except ImportError:
|
||||||
|
del ThreadMappedPool
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import doctest
|
import doctest
|
||||||
doctest.testmod()
|
doctest.testmod()
|
||||||
|
Reference in New Issue
Block a user