SUMMARY
This article demonstrates how to create a console
application that uses object pooling in Visual Basic .NET. You can turn on and
turn off object pooling to see how object pooling affects an application that
creates many expensive objects.
back to the top
Requirements
The following list outlines the recommended hardware, software,
network infrastructure, and service packs that you need:
- Microsoft .NET Framework
- Microsoft Windows 2000 Professional, Microsoft Windows 2000
Server, Microsoft Windows XP Professional, or Microsoft Windows XP
Server
This article assumes that you are familiar with the following
topics:
- Component Object Model (COM) and Enterprise
Services
- Object pooling
- Using attributes to extend metadata
back to the top
Create a Console Application in Visual Basic .NET
- Start Microsoft Visual Studio .NET.
- On the File menu, point to New, and then click New Project.
- In the New Project dialog box, click Visual Basic Projects under Project Types, and then click Console Application under Templates.
- In the Name text box, type PoolingDemo, and then click
OK.
- Make sure that the Solution Explorer window is visible. If
Solution Explorer is not visible, press the CTRL+ALT+L key
combination.
- Follow these steps to add a reference to the COM component
that you will be using:
- In Solution Explorer, right-click References, and then click Add Reference.
- On the .NET tab, click System.EnterpriseServices in the list of available components, and then click Select. Notice that System.EnterpriseServices appears in the Selected Components list.
- Click OK. Notice that System.EnterpriseServices appears under the References node in the console application.
back to the top
Add a Poolable and a Non-Poolable Class to the Project
- Right-click PoolingDemo in Solution Explorer, point to Add, and then click Add New Item.
- In the Add New Item dialog box, click Class under Templates, and then click Open. Class1.vb is created by default and contains both poolable and
non-poolable classes.
- To access object pooling attributes and members, add the
following code to the top of Class1.vb:
Imports System.EnterpriseServices
- Replace the default Class1 declaration with the following
code:
Public Class Poolable
Sub New()
Threading.Thread.Sleep(500)
End Sub
Public Sub DoSomething()
' Add method contents here.
End Sub
End Class
Notice that the constructor contains code that simulates an expensive
operation. - The object must inherit the ServicedComponent class to come under the control of the Component Services
runtime. Add the following code after the class declaration:
Inherits ServicedComponent
- To make this class poolable, follow these steps:
- The ObjectPoolingAttribute attribute, which is saved with the metadata of the class file,
flags the object for pooling at run time. Add the following code above the
Class declaration to add the ObjectPoolingAttribute attribute to the class:
<ObjectPooling(MinPoolSize:=0, MaxPoolSize:=1), JustInTimeActivation(True)> _
NOTE: Although the JustInTimeActivation attribute is not required to enable pooling, you may want to use
this attribute in most cases. Because it is expensive to create and to discard
components, you can improve performance significantly by allowing multiple
clients to reuse component instances. - The CanBePooledServicedComponent method returns False by default. To override the CanBePooled method so that the method returns True, add the following code:
Protected Overrides Function CanBePooled() As Boolean
Return True
End Function
- Add the following code to the non-poolable class:
Public Class NonPoolable
Inherits ServicedComponent
Sub New()
' Simulate an expensive operation.
Threading.Thread.Sleep(500)
End Sub
Public Sub DoSomething()
' Add method contents here.
End Sub
End Class
back to the top
Modify Module1.vb to Create Multiple Instances of These Classes
- In the Code Editor window, click the Module1.vb tab.
- At the top of the file, add the following Imports statement for the EnterpriseServices namespace to allow access to the DisposeObject method:
Imports System.EnterpriseServices
The DisposeOjbect method returns objects to the object pool, which allows them to
be reused. - Add the following Sub Main procedure:
Sub Main()
Dim StartTime As DateTime = DateTime.Now
Dim i As Int32
Const Iterations As Int16 = 50
For i = 1 To Iterations
Dim D As New NonPoolable()
D.DoSomething()
ServicedComponent.DisposeObject(D)
Next
Dim EndTime As DateTime = DateTime.Now
Dim Elapsed As TimeSpan = EndTime.Subtract(StartTime)
Dim OperationsPerSecond = Iterations / Elapsed.TotalSeconds
Console.WriteLine("Object Creations / Second = " & OperationsPerSecond)
System.Console.ReadLine()
End Sub
This code sets up a loop that creates an instance of the NonPoolable or the Poolable class during each of its 50 iterations. The code records the
start and the end times for the loop and then writes the number of objects that
are created per second to the console.
back to the top
Generate a Strong Name for the Assembly
You must generate a strong name for the assembly that this
project will generate. Without a strong name, you cannot use COM+ services to
register this assembly.
To generate this cryptographic key pair, use
the Strong Name (Sn.exe) tool, which is located in the Bin folder where the
.NET Framework Software Development Kit (SDK) is installed. Use the following
command-line syntax to run the Sn.exe tool:
sn -k drive letter\DirectoryToPlaceKey\KeyName.snk
- To open a Visual Studio .NET command prompt, click Start, point to Programs, point to Microsoft Visual Studio .NET, point to Visual Studio .NET Tools, and then click Visual Studio .NET Command
Prompt.
- At the command prompt, type the following command:
sn -k drive letter:\Project Root Folder\poolkey.snk
- Press the ENTER key to generate the key pair. Notice that
the following message appears in the command window:
- To associate this key with the project's assembly,
double-click AssemblyInfo.vb in Solution Explorer. By default, Visual Studio .NET includes
assembly attributes in this file when you create a project. Add the following
code to this list of assembly attributes:
<Assembly: AssemblyKeyFile("..\..\poolkey.snk")>
back to the top
Complete Code Listings
Class1.vb
Imports System.EnterpriseServices
<ObjectPooling(MinPoolSize:=0, MaxPoolSize:=1), JustInTimeActivation(True)> _
Public Class Poolable
Inherits ServicedComponent
Sub New()
' Simulate an expensive operation.
Threading.Thread.Sleep(500)
End Sub
Public Sub DoSomething()
' Add method contents here.
End Sub
Protected Overrides Function CanBePooled() As Boolean
Return True
End Function
End Class
Public Class NonPoolable
Inherits ServicedComponent
Sub New()
' Simulate an expensive operation.
Threading.Thread.Sleep(500)
End Sub
Public Sub DoSomething()
' Add method contents here.
End Sub
End Class
back to the top
Module1.vb
Imports System.EnterpriseServices
Module Module1
Sub Main()
Dim StartTime As DateTime = DateTime.Now
Dim i As Int32
Const Iterations As Int16 = 50
For i = 1 To Iterations
'Dim D As New Poolable()
Dim D As New NonPoolable()
D.DoSomething()
' To return the object to the object pool, use DisposeObject.
' This allows the object to be reused from the pool. If you do not call
' DisposeObject, the garbage collector does not collect this object,
' and the object is not reused from the object pool.
ServicedComponent.DisposeObject(D)
Next
Dim EndTime As DateTime = DateTime.Now
Dim Elapsed As TimeSpan = EndTime.Subtract(StartTime)
Dim OperationsPerSecond = Iterations / Elapsed.TotalSeconds
Console.WriteLine("Object Creations / Second = " & OperationsPerSecond)
' Pause until the user presses ENTER.
System.Console.ReadLine()
End Sub
End Module
back to the top
AssemblyInfo.vb
Imports System.Reflection
Imports System.Runtime.InteropServices
' The following set of attributes control general information about an assembly.
' Change these attribute values to modify the information that is associated with an assembly.
' Review the values of the assembly attributes.
<Assembly: AssemblyTitle("")>
<Assembly: AssemblyDescription("")>
<Assembly: AssemblyCompany("")>
<Assembly: AssemblyProduct("")>
<Assembly: AssemblyCopyright("")>
<Assembly: AssemblyTrademark("")>
<Assembly: CLSCompliant(True)>
<Assembly: AssemblyKeyFile("..\..\poolkey.snk")>
'The following GUID is for the ID of the TypeLib if you expose this project to COM.
<Assembly: Guid("30324ED6-329C-4B12-BDA2-8E817F1E2079")>
' Version information for an assembly consists of the following four values:
'
' Major Version
' Minor Version
' Build Number
' Revision
'
' You can specify all of these values, or you can use the asterisk (*) for
' the Build Number and the Revision values.
<Assembly: AssemblyVersion("1.0.*")>
back to the top
Verify That It Works
- Press the F5 key to run the application in debug mode.
Notice that this creates instances of the NonPoolable class.
- Wait approximately 25 seconds. Notice that the following
message appears:
Object Creations / Second = 1.73542243764044
NOTE: The exact number of creations per second may vary. - Press ENTER to exit the console application and to return
to Visual Studio .NET.
- Modify Module1.vb to create instances of the Poolable class. Change the first line in the Sub Main procedure as follows:
Dim D As New Poolable()
- Press F5 to run the application again.
- Wait a few seconds. Notice that the following message (or
similar) appears:
Object Creations / Second = 29.1977213631085
Note the significant improvement in performance when you use
object pooling. - Press ENTER to exit the console application and to return
to Visual Studio .NET.
back to the top
Troubleshooting
Do not forget to override
CanBePooled. If you omit this step, you cannot pool the
object.
back to the top
REFERENCES
For more information about how to implement and deploy COM+
configured classes by using the common language runtime, how to access object
context and call context, and how to manage context-relative object references,
refer to the following Microsoft Web site:
back to the top