Object pooling is pre-allocating a number of objects to use later. It is done by creating a group of objects (pool) initially and when you need an object, you take one from the pool rather than creating it. When you are done with the object you send it back to the pool. It effectively means reusing of objects. This allows bypassing the object creation overhead and reducing the work of garbage collector. Thus, managing the memory yourself. This is, of course, should be used with care because if you really want to manage the memory, why use a high-level language like Python?
Despite the fact that many programs don’t need object pooling, this technique can speed things up, especially in situations explained below.
There are two main reasons to use object pooling:
It is an optimization so it shouldn’t be applied until there is a proved bottleneck. It will increase the overall complexity of your program and probably present additional bugs. Also, when you create many objects at start, your program may allocate too much memory throughout its lifetime. As a result, you should carefully analyze the trade-off here.
The harbor example is from Paul Graham’s book ANSI Common Lisp. Here are two classes, one is using object pooling while the other is not.
class Ship():
def __init__(self):
self.name = None
self.flag = None
self.tons = None
class HarborWithPooling():
def __init__(self, count):
self.pool = [Ship() for i in range(count)]
self.harbor = {}
def enter(self, name, flag, tons):
ship = self.pool.pop()
ship.name = name
ship.flag = flag
ship.tons = tons
self.harbor[name] = ship
def find_ship(self, name):
return self.harbor[name]
def leave(self, name):
ship = self.harbor[name]
self.pool.append(ship)
del self.harbor[name]
class HarborWithoutPooling():
def __init__(self, count):
self.harbor = {}
def enter(self, name, flag, tons):
ship = Ship()
ship.name = name
ship.flag = flag
ship.tons = tons
self.harbor[name] = ship
def find_ship(self, name):
return self.harbor[name]
def leave(self, name):
ship = self.harbor[name]
del self.harbor[name]
Its execution time is measured while enter and leave methods are called 100,000 times in both classes. The test machine has an Intel Core 2 Duo 1.80GHz CPU and it is running Linux. Tested using Python 2.5.4. If you have time to test it on another version or OS, please let me know. You can download the complete source code here.
| Enter | Leave | Total | |
| With Object Pooling | 459 ms | 246 ms | 705 ms |
| Without Object Pooling | 952 ms | 224 ms | 1176 ms |
| Speed Up | %107 | -%9 | %66 |
There is about %66 overall speed increase when using object pooling.
Using object pooling in Python increases total object creation and destruction rate more than two-fold. When used appropriately, it will help developing fast Python programs. Particularly, the programs that needs to be fast such as games.
My name is Ertuğ Karamatlı. I'm working at sahibinden.com and doing a PhD in Computer Engineering at Boğaziçi University. Contact me at ertug@karamatli.com.
home · rss · knowledge base · twitter · github