Pond
Pond is a high-performance object-pooling library for Python, designed to reduce memory usage and improve object borrow hit rates. It provides thread-safe and coroutine-safe mechanisms for managing a pool of objects, automatically recycling infrequently used instances. Currently at version 1.4.1, Pond maintains an active development and release cadence, with its latest update in February 2024.
Warnings
- gotcha The PyPI package name is `pondpond`, but the library's primary import is `from pond import ...`. Attempting `from pondpond import ...` will result in an `ImportError` for top-level classes like `Pond` or `PooledObjectFactory`.
- breaking Starting from version 1.3.0, Pond replaced its internal `Queue` implementation with `deque` and `Count-min sketch` with the `madoka` library for significant performance improvements. While the public API for basic pooling operations (`borrow`, `recycle`) remains stable, any code that directly interacted with or relied on the specific internal data structures (e.g., inspecting the type of queue used) would be broken. This also introduces `madoka` as a new runtime dependency.
- deprecated In version 1.2.1, changes were made to align with Python's standard library updates. Specifically, `setDaemon()` for threads is deprecated in Python 3.9+, recommending the use of the `daemon` attribute directly instead. While this is a Python language change, it affects how `pondpond`'s internal threads are managed.
Install
-
pip install pondpond
Imports
- Pond
from pond import Pond
- PooledObjectFactory
from pond import PooledObjectFactory
Quickstart
import time
import threading
from pond import Pond, PooledObjectFactory
# Define a factory for the objects to be pooled
class MyObject:
def __init__(self, name):
self.name = name
self.created_at = time.time()
self.is_active = True
def do_work(self):
return f"Object {self.name} working. Active: {self.is_active}"
def cleanup(self):
self.is_active = False
return f"Object {self.name} cleaned up."
class MyObjectFactory(PooledObjectFactory):
def __init__(self, name_prefix):
self.name_prefix = name_prefix
self._counter = 0
self._lock = threading.Lock()
def create(self):
with self._lock:
self._counter += 1
obj = MyObject(f"{self.name_prefix}-{self._counter}")
print(f"Created: {obj.name}")
return obj
def destroy(self, obj):
print(f"Destroyed: {obj.cleanup()}")
def validate(self, obj):
# Example validation: object must be active
return obj.is_active
def activate(self, obj):
# Reset object state if necessary before borrowing
obj.is_active = True
print(f"Activated: {obj.name}")
return obj
def passivate(self, obj):
# Prepare object for recycling (e.g., clear transient data)
obj.is_active = False
print(f"Passivated: {obj.name}")
# Instantiate the Pond with our factory
# max_size: maximum number of objects to keep in the pool
# time_between_eviction_runs: interval in seconds for cleaning up idle objects
factory = MyObjectFactory("worker")
pool = Pond(factory, max_size=5, time_between_eviction_runs=5)
# Borrow objects
obj1 = pool.borrow()
print(obj1.do_work())
obj2 = pool.borrow()
print(obj2.do_work())
# Recycle objects
pool.recycle(obj1)
pool.recycle(obj2)
# Borrow again (should get recycled objects first)
obj3 = pool.borrow()
print(obj3.do_work())
# Simulate some time for eviction to run (if time_between_eviction_runs > -1)
print("Waiting for potential eviction...")
time.sleep(7)
# Close the pool to destroy all remaining objects
pool.close()
print("Pool closed.")