Object pool pattern

The object pool pattern is a software creational design pattern that uses a set of initialized objects kept ready to use – a "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 destroying it; this can be done manually or automatically.

Object pools are primarily used for performance: in some circumstances, object pools significantly improve performance. Object pools complicate object lifetime, as objects obtained from and returned to a pool are not actually created or destroyed at this time, and thus require care in implementation.

on demand 按照需要

Description

When it is necessary to work with a large number of objects that are particularly expensive to instantiate and each object is only needed for a short period of time, the performance of an entire application may be adversely affected. An object pool design pattern may be deemed desirable in cases such as these.

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 framework. One example is the .NET Framework Data Provider for SQL Server. As SQL Server database connections can be slow to create, a pool of connections is maintained.  it does not actually relinquish the link to SQL Server. Instead, the connection is held in a pool from which it can be retrieved when requesting a new connection. This substantially increases the speed of making connections.When you close a connection

adversely 不利地  [æd'vɝsli]

deem 认为

computational 计算的

relinquish  放弃

substantially  实质上;大体上;充分地

significant 显著的

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.[1] 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.

performance boost  性能提升

destruction  破坏,毁灭;摧毁

preferable  更好的,更可取的;更合意的

predictable  可预言的

external   外部的;表面的;[药] 外用的;外国的;外面的

deallocation  存储单元分配;重新分配地址

fragmentation  破碎;分裂;[计] 存储残片

Implementation

Object pools can be implemented in an automated fashion in languages like C++ via smart pointers. In the constructor of the smart pointer - an object can be requested from the pool and in the destructor of the smart pointer - the object can be released back to the pool. In garbage collected languages, where there are no destructors (which are guaranteed to be called as part of a stack unwind) - object pools MUST be implemented in a manual fashion, by explicitly requesting an object from the factory and returning the object by calling a dispose method (as in the dispose pattern). Using a finalizer to do this is not a good idea as there are usually no guarantees on when (or if ever) the finalizer will be run. Instead - prefer using try ... finally to ensure that getting and releasing the object is exception neutral.

Manual object pools are simple to implement, but harder to use, as they require manual memory management of pool objects.

automated fashion 自动化的方式

stack unwind 栈展开,栈回退

exception neutral 异常中立

Handling of empty pools

Object pools employ one of three strategies to handle a request when there are no spare objects in the pool.

  1. Fail to provide an object (and return an error to the client).
  2. Allocate a new object, thus increasing the size of the pool. Pools that do this usually allow you to set the high water mark (the maximum number of objects ever used).
  3. In a multithreaded environment, a pool may block the client until another thread returns an object to the pool.     

spare 多余的;瘦的;少量的

Pitfalls

When writing an object pool, the programmer has to be careful to make sure the state of the objects returned to the pool is reset back to a sensible state for the next use of the object. If this is not observed, the object will often be in some state that was unexpected by the client program and may cause the client program to fail. The pool is responsible for resetting the objects, not the clients. Object pools full of objects with dangerously stale state are sometimes called object cesspools and regarded as an anti-pattern.

The presence of stale state is not always an issue; it becomes dangerous when the presence of stale state causes the object to behave differently. For example, an object that represents authentication details may break if the "successfully authenticated" flag is not reset before it is passed out, since it will indicate that a user is correctly authenticated (possibly as someone else) when they haven't yet attempted to authenticate. However, it will work just fine if you fail to reset some value only used for debugging, such as the identity of the last authentication server used.

Inadequate resetting of objects may also cause an information leak. If an object contains confidential data (e.g. a user's credit card numbers) that isn't cleared before the object is passed to a new client, a malicious or buggy client may disclose the data to an unauthorized party.

If the pool is used by multiple threads, it may need the means to prevent parallel threads from grabbing and trying to reuse the same object in parallel. This is not necessary if the pooled objects are immutable or otherwise thread-safe.

单词:

pitfall  陷阱;诱惑

cesspool  污水坑;粪坑;污秽场所

presence 存在;出席;参加;风度;仪态

stale 陈腐的;不新鲜的

authentication server  认证服务器 ; 验证服务器 ; 认证伺服器 ; 验证伺服器

inadequate  不充分的,不适当的

leak  泄漏;漏洞,裂缝

confidential 机密的;表示信任的;获信任的

malicious  恶意的;恶毒的;蓄意的;怀恨的

immutable  不变的;不可变的;不能变的

Criticism

Some publications do not recommend using object pooling with certain languages, such as Java, especially for objects that only use memory and hold no external resources.[2] Opponents usually say that object allocation is relatively fast in modern languages with garbage collectors; while the operator new needs only ten instructions, the classic new - delete pair found in pooling designs requires hundreds of them as it does more complex work. Also, most garbage collectors scan "live" object references, and not the memory that these objects use for their content. This means that any number of "dead" objects without references can be discarded with little cost. In contrast, keeping a large number of "live" but unused objects increases the duration of garbage collection.[1] In some cases, programs that use garbage collection instead of directly managing memory may run faster.

 Criticism 批评;考证;苛求

publication 出版;出版物;发表

Opponent 对手;反对者;敌手

instruction 指令,命令;指示;教导;用法说明

discard 抛弃;放弃;丢弃

in contrast 与此相反;比较起来

duration  持续,持续的时间,期间

 

最后附上C#的代码示例

In the .NET Base Class Library there are a few objects that implement this pattern. System.Threading.ThreadPool is configured to have a predefined number of threads to allocate. When the threads are returned, they are available for another computation. Thus, one can use threads without paying the cost of creation and disposal of threads.

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.

computation 估计,计算

disposal  处理;支配;清理;安排

brevity  简洁,简短;短暂,短促

unusual  不寻常的;与众不同的;不平常的

 

/// <summary>
    /// 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.
    /// </summary>
    public class PooledObject
    {
        private DateTime createdAt = DateTime.Now;
        public DateTime CreatedAt
        {
            get { return createdAt; }
        }

        public string TempData { get; set; }
    }

/// <summary>
    /// The Pool class is the most important class in the object pool design pattern. It controls access to the
    /// pooled objects, maintaining a list of available objects and a collection of objects that have already been
    /// requested from the pool and are still in use. The pool also ensures that objects that have been released
    /// are returned to a suitable state, ready for the next time they are requested. 
    /// </summary>
    public static class Pool
    {
        private static SynchronizedCollection<PooledObject> avaiable = new SynchronizedCollection<PooledObject>();
        private static SynchronizedCollection<PooledObject> inUse = new SynchronizedCollection<PooledObject>();

        public static PooledObject GetObject()
        {
            PooledObject po = null;
            if (avaiable.Count == 0)
            {
                po = new PooledObject();
                inUse.Add(po);
            }
            else
            {
                po = avaiable[0];
                inUse.Add(po);
                avaiable.RemoveAt(0);
            }
            return po;
        }

        public static void ReleaseObject(PooledObject po)
        {
            CleanUp(po);
            avaiable.Add(po);
            inUse.Remove(po);
        }

        private static void CleanUp(PooledObject po)
        {
            po.TempData = null;
        }
    }

 

 

In the code above, the PooledObject includes two properties that are not shown in the UML diagram. One holds the time at which the object was first created. The other holds a string that can be modified by the client but that is reset when the PooledObject is released back to the pool. This shows the clean-up process on release of an object that ensures it is in a valid state before it can be requested from the pool again.

 

http://en.wikipedia.org/wiki/Object_pool_pattern    维基百科的解释