概要
Poolパターンは、独立した状態の再利用可能なオブジェクトを作成して維持する。
プール自体はイテレート可能であり、ユーザーのケースに合わせて任意の方法で実装できる。重要なのは、オブジェクトのインスタンス化の数を最小限にすること。このパターンは以下のような場合に有効。
- 新しいオブジェクトの構築にコストがかかる(時間的、空間的、帯域幅的な複雑さ)
- オブジェクトを頻繁に出し入れする必要があるが、用途ごとに固有のオブジェクトを用意する必要がない
- 常に少量のインスタンスしか使用していない
シンプルなワーカープールを実装例に示す。ワーカーをアクティブ/非アクティブにしたり、プールのサイズを管理するためのインターフェイスを実装する。
実装例
WorkerPool クラスが、ワーカーの作成と削除を制御する。ケースに応じて、シングルトンとして実装すると便利。オブジェクトの作成に時間がかかるような複雑なケースでは、プール内のワーカーを初期化するロジックをWorkerPoolのコンストラクタから分離すると良い可能性がある。
ワーカーが有効化されると、プールはアクティブなワーカーのリストを維持しつつ、_workersリストから削除する。ワーカーが無効化されると、_workersリストに戻される。Worker オブジェクトが内部状態を保持している場合、リセットする(またはデフォルトの休止状態に設定する)のに良いタイミング。
実行中にワーカープールのサイズを変更する必要がある場合、理想的なソリューションは、直後に再作成する必要のあるワーカーを削除せずにサイズ変更を実行すること。実装例のresizeメソッドでは、サイズ変更される数が制限内であることと、このプロセスがアクティブなワーカーに影響を与えないことを保証しながら、この問題に対処する方法の1つを示す。
class WorkerPoolError(Exception):
pass
class Worker:
pass
class WorkerPool:
limit = 4
def __init__(self, count):
self.within_limit_check(count)
self._workers = [Worker() for n in range(count)]
self.active_count = 0
def within_limit_check(self, count):
if count > WorkerPool.limit or count <= 0:
raise WorkerPoolError("Valid Worker Size")
return True
def activate_worker(self):
self.active_count += 1
return self._workers.pop()
def deactivate_worker(self, worker):
self.active_count -= 1
self._workers.append(worker)
def resize(self, new_count):
self.within_limit_check(new_count)
total_workers = len(self._workers) + self.active_count
diff = new_count - total_workers
if diff == 0:
pass
elif diff > 0:
for n in range(diff):
self._workers.append(Worker())
elif diff < 0:
if diff > len(self._workers):
raise WorkerPoolError("Valid Worker Size")
else:
for n in range(abs(diff)):
self._workers.pop()
if __name__ == "__main__":
print("Creating Worker pool, 3 Workers...")
worker_pool = WorkerPool(3)
print("Activating 1 Worker...")
worker_1 = worker_pool.activate_worker()
print("Deactivating 1 Worker...")
worker_pool.deactivate_worker(worker_1)
print("Active Worker Size:", worker_pool.active_count)
print("Resizing pool 4 Workers...")
worker_pool.resize(4)
print("Total Workers: ", len(worker_pool._workers) + worker_pool.active_count)
print("Resizing pool 2 Workers...")
worker_pool.resize(2)
print("Total Workers: ", len(worker_pool._workers) + worker_pool.active_count)