Content deleted Content added
→See also: add portal |
|||
(38 intermediate revisions by 29 users not shown) | |||
Line 1:
{{Short description|Software creational design pattern}}
{{for|the article about a general pool|Pool (computer science)}}
The '''object pool pattern''' is a software [[creational pattern|creational design pattern]] that uses a set of initialized [[Object (computer science)|objects]] kept ready to use – a "[[Pool (computer science)|pool]]" – rather than allocating and destroying them on demand. A client of the pool will request an object from the pool and perform operations on the returned object. When the client has finished, it returns the object to the pool rather than [[object destruction|destroying it]]; this can be done manually or automatically.
Line 6:
== Description ==
When it is necessary to work with
The object pool design pattern creates a set of objects that may be reused. When a new object is needed, it is requested from the pool. If a previously prepared object is available, it is returned immediately, avoiding the instantiation cost. If no objects are present in the pool, a new item is created and returned. When the object has been used and is no longer needed, it is returned to the pool, allowing it to be used again in the future without repeating the computationally expensive instantiation process. It is important to note that once an object has been used and returned, existing references will become invalid.
In some object pools the resources are limited, so a maximum number of objects is specified. If this number is reached and a new item is requested, an exception may be thrown, or the thread will be blocked until an object is released back into the pool.
The object pool design pattern is used in several places in the standard classes of the .NET
== Benefits ==
Object pooling can offer a significant performance boost in situations where the cost of initializing a class instance is high and the rate of instantiation and destruction of a class is high – in this case objects can frequently be reused, and each reuse saves a significant amount of time. Object pooling requires resources – memory and possibly other resources, such as network sockets, and thus it is preferable that the number of instances in use at any one time is low, but this is not required.
The pooled object is obtained in predictable time when creation of the new objects (especially over network) may take variable time. These benefits are mostly true for objects that are expensive with respect to time, such as database connections, socket connections, threads and large graphic objects like fonts or bitmaps.
In other situations, simple object pooling (that hold no external resources, but only occupy memory) may not be efficient and could decrease performance.<ref name="urban">{{cite web|last1=Goetz|first1=Brian|date=2005-09-27|title=Java theory and practice: Urban performance legends, revisited|url=http://www.ibm.com/developerworks/java/library/j-jtp09275/index.html|url-status=dead|archive-url=https://web.archive.org/web/20120214195433/http://www.ibm.com/developerworks/java/library/j-jtp09275/index.html|archive-date=2012-02-14|access-date=2021-03-15|website=[[IBM]]|publisher=IBM developerWorks}}</ref> In case of simple memory pooling, the [[slab allocation]] memory management technique is more suited, as the only goal is to minimize the cost of memory allocation and deallocation by reducing fragmentation.
== Implementation ==
Object pools can be implemented in an automated fashion in languages like C++ via [[Smart pointer|smart pointers]]. In the constructor of the smart pointer
Manual object pools are simple to implement, but harder to use, as they require [[manual memory management]] of pool objects.
== Handling of empty pools ==
Line 49 ⟶ 36:
== Pitfalls ==
Inadequate resetting of objects
If the pool is used by multiple threads, it may need the means to prevent parallel threads from
== Criticism ==
Some publications do not recommend using object pooling with certain languages, such as [[Java (programming language)|Java]], especially for objects that only use memory and hold no external resources (such as connections to database). Opponents usually say that object allocation is relatively fast in modern languages with [[Garbage collection (computer science)|garbage collectors]]; while the operator <
== Examples ==
=== Go ===
The following Go code initializes a resource pool of a specified size (concurrent initialization) to avoid resource race issues through channels, and in the case of an empty pool, sets timeout processing to prevent clients from waiting too long.
<syntaxhighlight lang=Go>
// package pool
package pool
import (
"errors"
"log"
"math/rand"
"sync"
"time"
)
const getResMaxTime = 3 * time.Second
var (
ErrPoolNotExist = errors.New("pool not exist")
ErrGetResTimeout = errors.New("get resource time out")
)
//Resource
type Resource struct {
resId int
}
//NewResource Simulate slow resource initialization creation
// (e.g., TCP connection, SSL symmetric key acquisition, auth authentication are time-consuming)
func NewResource(id int) *Resource {
time.Sleep(500 * time.Millisecond)
return &Resource{resId: id}
}
//Do Simulation resources are time consuming and random consumption is 0~400ms
func (r *Resource) Do(workId int) {
time.Sleep(time.Duration(rand.Intn(5)) * 100 * time.Millisecond)
log.Printf("using resource #%d finished work %d finish\n", r.resId, workId)
}
//Pool based on Go channel implementation, to avoid resource race state problem
type Pool chan *Resource
//New a resource pool of the specified size
// Resources are created concurrently to save resource initialization time
func New(size int) Pool {
p := make(Pool, size)
wg := new(sync.WaitGroup)
wg.Add(size)
for i := 0; i < size; i++ {
go func(resId int) {
p <- NewResource(resId)
wg.Done()
}(i)
}
wg.Wait()
return p
}
//GetResource based on channel, resource race state is avoided and resource acquisition timeout is set for empty pool
func (p Pool) GetResource() (r *Resource, err error) {
select {
case r := <-p:
return r, nil
case <-time.After(getResMaxTime):
return nil, ErrGetResTimeout
}
}
//GiveBackResource returns resources to the resource pool
func (p Pool) GiveBackResource(r *Resource) error {
if p == nil {
return ErrPoolNotExist
}
p <- r
return nil
}
// package main
package main
import (
"github.com/tkstorm/go-design/creational/object-pool/pool"
"log"
"sync"
)
func main() {
// Initialize a pool of five resources,
// which can be adjusted to 1 or 10 to see the difference
size := 5
p := pool.New(size)
// Invokes a resource to do the id job
doWork := func(workId int, wg *sync.WaitGroup) {
defer wg.Done()
// Get the resource from the resource pool
res, err := p.GetResource()
if err != nil {
log.Println(err)
return
}
// Resources to return
defer p.GiveBackResource(res)
// Use resources to handle work
res.Do(workId)
}
// Simulate 100 concurrent processes to get resources from the asset pool
num := 100
wg := new(sync.WaitGroup)
wg.Add(num)
for i := 0; i < num; i++ {
go doWork(i, wg)
}
wg.Wait()
}
</syntaxhighlight>
=== C# ===
Line 78 ⟶ 171:
The following shows the basic code of the object pool design pattern implemented using C#. For brevity the properties of the classes are declared using C# 3.0 automatically implemented property syntax. These could be replaced with full property definitions for earlier versions of the language. Pool is shown as a static class, as it's unusual for multiple pools to be required. However, it's equally acceptable to use instance classes for object pools.
<
namespace DesignPattern.Objectpool;
// The PooledObject class is the type that is expensive or slow to instantiate,
// or that has limited availability, so is to be held in the object pool.
public class PooledObject
{
private DateTime _createdAt = DateTime.Now;
public DateTime CreatedAt => _createdAt;
public string TempData { get; set; }
}
// The Pool class
//
// are returned to a suitable state, ready for reuse.
public static class Pool
{
private static List<PooledObject> _available = new List<PooledObject>();
private static List<PooledObject> _inUse = new List<PooledObject>();
public static PooledObject GetObject()
{
lock (_available)
{
if (_available.Count != 0)
Line 124 ⟶ 212:
}
}
public static void ReleaseObject(PooledObject po)
{
CleanUp(po);
lock (_available)
{
Line 135 ⟶ 223:
}
}
private static void CleanUp(PooledObject po)
{
Line 141 ⟶ 229:
}
}
</syntaxhighlight>
In the code above, the PooledObject has properties for the time it was created, and another, that can be modified by the client, that is reset when the PooledObject is released back to the pool. Shown is the clean-up process, on release of an object, ensuring it is in a valid state before it can be requested from the pool again.
=== Java ===
Java supports [[Thread pool pattern|thread pooling]] via <code>java.util.concurrent.ExecutorService</code> and other related classes. The executor service has a certain number of "basic" threads that are never discarded. If all threads are busy, the service allocates the allowed number of extra threads that are later discarded if not used for the certain expiration time. If no more threads are allowed, the tasks can be placed in the queue. Finally, if this queue may get too long, it can be configured to suspend the requesting thread.
<syntaxhighlight lang="java">
public class PooledObject {
public String temp1;
public String temp2;
public String temp3;
public String getTemp1() {
return temp1;
}
public void setTemp1(String temp1) {
this.temp1 = temp1;
}
public String getTemp2() {
return temp2;
}
public void setTemp2(String temp2) {
this.temp2 = temp2;
}
public String getTemp3() {
return temp3;
}
public void setTemp3(String temp3) {
this.temp3 = temp3;
}
}
</syntaxhighlight><syntaxhighlight lang="java">
public class PooledObjectPool {
private static long expTime = 6000;//6 seconds
public static HashMap<PooledObject, Long> available = new HashMap<PooledObject, Long>();
public static HashMap<PooledObject, Long> inUse = new HashMap<PooledObject, Long>();
public synchronized static PooledObject getObject() {
long now = System.currentTimeMillis();
if (!available.isEmpty()) {
for (Map.Entry<PooledObject, Long> entry : available.entrySet()) {
if (now - entry.getValue() > expTime) { //object has expired
popElement(available);
} else {
PooledObject po = popElement(available, entry.getKey());
push(inUse, po, now);
return po;
}
}
}
// either no PooledObject is available or each has expired, so return a new one
return createPooledObject(now);
}
private synchronized static PooledObject createPooledObject(long now) {
PooledObject po = new PooledObject();
push(inUse, po, now);
return po;
}
private synchronized static void push(HashMap<PooledObject, Long> map,
PooledObject po, long now) {
map.put(po, now);
}
public static void releaseObject(PooledObject po) {
cleanUp(po);
available.put(po, System.currentTimeMillis());
inUse.remove(po);
}
private static PooledObject popElement(HashMap<PooledObject, Long> map) {
Map.Entry<PooledObject, Long> entry = map.entrySet().iterator().next();
PooledObject key= entry.getKey();
//Long value=entry.getValue();
map.remove(entry.getKey());
return key;
}
private static PooledObject popElement(HashMap<PooledObject, Long> map, PooledObject key) {
map.remove(key);
return key;
}
public static void cleanUp(PooledObject po) {
po.setTemp1(null);
po.setTemp2(null);
po.setTemp3(null);
}
}
</syntaxhighlight>
== See also ==
{{Portal|Computer programming}}
* [[Connection pool]]
* [[Free list]]
* [[Slab allocation]]
==
{{reflist|30em}}
==References==
{{refbegin}}
*{{cite conference
Line 165 ⟶ 340:
|author2=Prashant Jain
| title = Pooling Pattern
|
| place = Germany
| date = 2002-07-04
| url = http://www.kircher-schwanninger.de/michael/publications/Pooling.pdf
|
* {{Cite book | isbn = 978-1-4302-4458-5 | title = Pro .NET Performance: Optimize Your C# Applications | last1 = Goldshtein | first1 = Sasha | last2 = Zurbalev | first2 = Dima | last3 = Flatow | first3 = Ido | year = 2012 | publisher = Apress | url = http://www.apress.com/9781430244585
{{refend}}
== External links ==
* [http://www.oodesign.com/object-pool-pattern.html OODesign article]
* [http://msdn2.microsoft.com/en-us/library/ms682822.aspx Improving Performance with Object Pooling (Microsoft Developer Network )]
Line 185 ⟶ 360:
[[Category:Software design patterns]]
[[Category:Software optimization]]
[[Category:Articles with example C Sharp code]]
[[Category:Articles with example Java code]]
|