Using ConcurrentQueue for thread-safe Performance Bookkeeping.

Posted by Strenium on Geeks with Blogs See other posts from Geeks with Blogs or by Strenium
Published on Fri, 06 Apr 2012 04:03:29 GMT Indexed on 2012/04/06 5:30 UTC
Read the original article Hit count: 223

Filed under:

Just a small tidbit that's sprung up today.

I had to book-keep and emit diagnostics for the average thread performance in a highly-threaded code over a period of last X number of calls and no more. Need of the day: a thread-safe, self-managing stats container.

Since .NET 4.0 introduced new thread-safe 'Collections.Concurrent' objects and I've been using them frequently - the one in particular seemed like a good fit for storing each threads' performance data - ConcurrentQueue.

But I wanted to store only the most recent X# of calls and since the ConcurrentQueue currently does not support size constraint I had to come up with my own generic version which attempts to restrict usage to numeric types only: unfortunately there is no IArithmetic-like interface which constrains to only numeric types – so the constraints here here aren't as elegant as they could be. (Note the use of the Average() method, of course you can use others as well as make your own).

 

FIFO FixedSizedConcurrentQueue
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Linq;
  4.  
  5. namespace xxxxx.Data.Infrastructure
  6. {
  7.     [Serializable]
  8.     public class FixedSizedConcurrentQueue<T> where T : struct, IConvertible, IComparable<T>
  9.     {
  10.         private FixedSizedConcurrentQueue() { }
  11.  
  12.         public FixedSizedConcurrentQueue(ConcurrentQueue<T> queue)
  13.         {
  14.             _queue = queue;
  15.         }
  16.  
  17.         ConcurrentQueue<T> _queue = new ConcurrentQueue<T>();
  18.  
  19.         public int Size { get { return _queue.Count; } }
  20.         public double Average { get { return _queue.Average(arg => Convert.ToInt32(arg)); } }
  21.  
  22.         public int Limit { get; set; }
  23.         public void Enqueue(T obj)
  24.         {
  25.             _queue.Enqueue(obj);
  26.             lock (this)
  27.             {
  28.                 T @out;
  29.                 while (_queue.Count > Limit) _queue.TryDequeue(out @out);
  30.             }
  31.         }
  32.     }
  33.  
  34. }

 

The usage case is straight-forward, in this case I’m using a FIFO queue of maximum size of 200 to store doubles to which I simply Enqueue() the calculated rates:

Usage
  1. var RateQueue = new FixedSizedConcurrentQueue<double>(new ConcurrentQueue<double>()) { Limit = 200 }; /* greater size == longer history */

 

That’s about it. Happy coding!

© Geeks with Blogs or respective owner