Performance programming for WebSphere eXtreme Scale Client for .NET
You must consider the effects that the .NET APIs have on the performance of your .NET application. The management of the data grid, map objects, and threads also influences application performance.
IGridMapPessimisticAutoTx API versus IGridMapPessimisticTx API
When you are using only Get or GetAll methods to retrieve data from the grid, the IGridMapPessimisticAutoTx.Get and IGridMapPessimisticAutoTx.GetAll methods are faster than the counterpart IGridMapPessimisticTx methods. This performance increase is because the shared lock is automatically freed during the IGridMapPessimisticAutoTx API Get and GetAll method calls. In contrast, the shared lock that is set by the IGridMapPessimisticTx API Get and GetAll methods is not freed until the Commit method call, resulting in another client/server request and response.IGridMapPessimisticAutoTx<object,object> autoTxMap =
grid.GetGridMapPessimisticAutoTx<object,object>("Map");
IGridMapPessimisticTx<object,object> manualTxMap =
grid.GetGridMapPessimisticTx<object,object>("Map");
// 1 remote grid access
object autoVal = autoTxMap.Get(key);
// 2 remote grid accesses
manualTxMap.Transaction.Begin();
object manualVal = manualTxMap.Get(key); // first remote grid access to get and lock item
manualTxMap.Transaction.Commit(); // second remote grid access to release the shared lock
For
more information about locking behavior, see Configuring and implementing locking in .NET applications.Batch APIs
WebSphere eXtreme Scale Client for .NET provides a matching batch API for each API that operates on a single data grid item. Some of these batch APIs result in a single request that is sent to the data grid. However, a few other batch APIs exist that result in multiple requests to be sent to the data grid. Limit the use of these convenience APIs when you are optimizing the .NET application for performance. The following WebSphere eXtreme Scale Client for .NET batch APIs result in one data grid request no matter how many items are in the batch list:- IGridMapPessimisticAutoTx.GetAll, IGridMapPessimisticTx.GetAll
- IGridMapPessimisticAutoTx.InvalidateAll, IGridMapPessimisticTx.InvalidateAll
- IGridMapPessimisticAutoTx.PutAll, IGridMapPessimisticTx.PutAll
- IGridMapPessimisticAutoTx.RemoveAll, IGridMapPessimisticTx.RemoveAll
- IGridMapPessimisticTx.LockAll
- IGridMapPessimisticTx.GetAndLockAll
- IGridMapPessimisticAutoTx.ContainsKeyAll, IGridMapPessimisticTx.ContainsKeyAll
- IGridMapPessimisticAutoTx.AddAll, IGridMapPessimisticTx.AddAll
- IGridMapPessimisticAutoTx.ReplaceAll, IGridMapPessimisticTx.ReplaceAll
- IGridMapPessimisticAutoTx.TouchAll, IGridMapPessimisticTx.TouchAll
Pooling data grid and map objects
.NET application processor and memory usage increase when you instantiate IGrid, IGridMapPessimisticAutoTx, and IGridMapPessimisticTx objects. Where possible, maintain the minimum number of these instances. Grid objects are thread safe. A single instance can be shared across all threads in the process. Map objects, such as IGridMapPessimisticAutoTx and IGridMapPessimisticTx objects, are not thread safe, so each concurrent thread requires a separate map object instance. If your .NET application accesses the data grid from many different threads, maintain a thread-accessible pool of map object instances. This pool prevents the constant recreation of map instances. The following code sample shows a map instance pool implementation:
using System;
using System.Collections.Concurrent;
using System.Threading;
using IBM.WebSphere.Caching;
using IBM.WebSphere.Caching.Map;
namespace NetClientPooledMapExample
{
class Program
{
private static ConcurrentQueue<IGridMapPessimisticAutoTx<string, string>> autoTxMapQ =
new ConcurrentQueue<IGridMapPessimisticAutoTx<string, string>>();
private static IGridManager gm = null;
private static ICatalogDomainInfo cdi = null;
private static IClientConnectionContext ctx = null;
private static IGrid g = null;
static void Main(string[] args)
{
int numThreads = 50; // Number of concurrent threads accessing the same map
try
{
gm = GridManagerFactory.GetGridManager();
cdi = gm.CatalogDomainManager.CreateCatalogDomainInfo("localhost:2809");
ctx = gm.Connect(cdi);
g = gm.GetGrid(ctx, "Grid");
Thread[] tArray = new Thread[numThreads];
for (int i = 0; i < numThreads; i++)
{
tArray[i] = new Thread(PopulateGrid);
tArray[i].Start();
}
for (int i = 0; i < numThreads; i++)
{
tArray[i].Join();
}
}
catch (Exception e)
{
Console.WriteLine("Encountered exception during grid access: {0}", e);
}
finally
{
if (gm != null && ctx != null)
{
gm.Disconnect(ctx);
}
}
}
private static void PopulateGrid()
{
IGridMapPessimisticAutoTx<string, string> gridMapAuto = null;
string key = "Key_" + Thread.CurrentThread.ManagedThreadId;
string value = "Val_" + Thread.CurrentThread.ManagedThreadId;
try
{
// Pull an available map off the queue
gridMapAuto = GetAutoTxMap(g, "Map1");
// Do some work with the map
gridMapAuto.Put(key, value);
Console.WriteLine("Thread {0} wrote key {1} with value {2}",
Thread.CurrentThread.ManagedThreadId, key, value);
}
catch (Exception e)
{
Console.WriteLine("Encountered exception during map access: {0}", e);
}
finally
{
// Release the map to the queue when done
ReleaseAutoTxMap(gridMapAuto);
}
}
private static IGridMapPessimisticAutoTx<string, string> GetAutoTxMap(IGrid grid, string mapName)
{
IGridMapPessimisticAutoTx<string, string> retmap = null;
if (!autoTxMapQ.TryDequeue(out retmap))
{
// Create a new map if the queue is out of available maps
retmap = grid.GetGridMapPessimisticAutoTx<string, string>(mapName);
}
return retmap;
}
private static void ReleaseAutoTxMap(IGridMapPessimisticAutoTx<string, string> map)
{
autoTxMapQ.Enqueue(map);
}
}
}