Understanding .NET pooling

.NET pooling enables you to create a “pool” of objects that are active and ready to use when a client sends a request. You can specify the minimum and maximum pool size, time‑out values, and whether objects in the pool should be reused.

Depending on the requirements of your application, pooling can significantly improve performance by reducing the time necessary to create objects, establish connections, and perform initialization processing. Pooling is most beneficial when objects are used frequently for a short time, and a significant portion of that time is spent acquiring the connection and performing initialization processing. However, any time there is initialization code that needs to be run, pooling should improve the performance of your application.

How pooling works

The type of pooling supported by xfNetLink .NET is referred to as object pooling. Object pooling creates a pool of Synergy .NET objects. (These are objects instantiated from the procedural classes in your Synergy assembly; objects instantiated from structure classes are not pooled.)

When the pool is created, the objects are instantiated and connected to xfServerPlus. The pool is populated with the minimum number of objects that you specify when you define the pool. When a client requests an object, the request is satisfied from the objects available in the pool. If no object is available, a new one is created, up to the maximum size of the pool. Once the maximum is reached, requests are queued for a specified length of time. When the client releases an object, you can specify that it be either returned to the pool or discarded. (If it is discarded, causing the number of objects in the pool to drop below the minimum size, a new object will be created.)

If desired, you can write an initialization method that will be run automatically after the connection is established. There are several other methods that can be used with pooled objects to perform initialization and cleanup tasks. (See Using the pooling support methods.)

Reusing objects

After an object has been used, it can either be returned to the pool for reuse or discarded. By default, all objects are discarded after use; however, we recommend returning objects to the pool if possible because it can improve performance. Discarding an object releases resources and ensures that the next client request receives a “clean” object. In general, stateless objects may be returned to the pool, while objects with state (that is, those that persist data) should be discarded after use. If you decide to reuse objects, you can perform cleanup processing with the pooling support methods.

To specify that an object be returned to the pool, in the xfNetLink .NET Configuration Utility, select the pool return key and select the “Return objects to pool” checkbox (see pool return in the Class Settings table). You can also determine at runtime if an object should be reused using the CanBePooled() method (see CanBePooled() ).

Creating poolable objects

To enable the classes in an assembly to be pooled, select the “Support pooling” checkbox in the Component Information dialog box in Workbench. (Or, from the command line, specify the ‑p option when you run the batch file to build the assembly.)

When you build an assembly with pooling enabled, all procedural classes within the assembly become components in the pool. (Note that if you created multiple instances of the same class, each instance becomes a component in the pool.) Depending on your application, you may not want to pool all classes in an assembly. When deciding how to group interfaces into assemblies, you should take into account which classes you want pooled.

Each pooled object represents a connection, which means that it requires an xfServerPlus license. Consequently, when deciding which classes to pool and how large to make the pool, you should ensure that the maximum number of all pooled objects does not exceed the available licenses.

To obtain the greatest benefit from pooling, when writing your Synergy routines you should separate out the initialization and resource acquisition code that is performed for all clients as a prerequisite to doing the work of the object. This code can then go in the Initialize() method, to be executed when the object is created. Or, depending on the needs of your application, this code may go in the Activate() method to be executed when the object is retrieved from the pool by a client.