« Don't you love the web...Object pooling, part 6 - growing and shrinking »

Object pooling, part 7 - the first test program

25/09/05

Permalink 03:31:19 pm
Categories: General, Programming, .NET

Object pooling, part 7 - the first test program

This is the seventh article in my mini series about object pooling. Be sure to read part 1, part 2, part 3, part 4, part 5 and part 6 first.

As some of you may have noticed, I introduced a bad bug in the last article about growing and shrinking, specifically in the code that would call the ExtendPoolBy and ShrinkPoolBy methods. The amount by which to grow or shrink the pool was calculated as the difference between two percentage figures and passed in to the two methods, which really expected absolute values! That's what I get for not using test-first development on this :-)

So I fixed this and introduced two simple algorithms instead to handle the calculation of the growing and shrinking amounts. This is quite an important topic for object pooling, because it defines how well the pool scales in various scenarios - sometimes it may be desirable to have a pool that adapts quickly to new requirements, sometimes it's more important to keep the pool size stable as long as possible. In one of the next posts in the series I'm going to factor out the growing/shrinking behaviour using the strategy pattern, until then the current calculation will have to do - and the new test program shows that it doesn't do that bad at all!

The test program

Here's the download of the current code and the sample program. This has been created in Visual Studio 2005 beta 2.

As promised, I have created a test program that uses a few threads to do work with the pool. Each thread runs a loop in which a number of objects is requested from the pool and released after a while. A random values determines if only a single object or a larger number of objects will be requested in each run. Here's the code:

  class Program : IObjectFactory<PoolableObject> {
    static void Main(string[] args) {
      new Program( ).Run( );
    }
		
    Pool<PoolableObject> pool;
    private const int threadCount = 3;

    void Run( ) {
      pool = new Pool<PoolableObject>(this, 0);
      pool.UseTimerBasedResizing = true;
      pool.MaxPoolSize = 100;

      Thread[] threads = new Thread[threadCount];
      for (int i = 0; i < threadCount; i++) {
        threads[i] = new Thread(new ThreadStart(ThreadMethod));
        threads[i].Start( );
      }

      while (true) {
        Console.WriteLine("Current pool size: " + pool.Size);
        Thread.Sleep(2000);
      }
    }

    void ThreadMethod( ) {
      Random random = new Random( );
      while (true) {
        if (random.Next(0, 100) > 50) {
          // boost
          int boostSize = random.Next(5, 20);
          PoolableObject[] objects = new PoolableObject[boostSize];
          for (int i = 0; i < boostSize; i++) {
            objects[i] = pool.GetObject( );
            Console.WriteLine(String.Format("Thread {0} allocated object {1}.", 
              Thread.CurrentThread.ManagedThreadId, objects[i].Id));
            objects[i].DoWork( );
          }
          Thread.Sleep(random.Next(0, 5000));
          for (int i = 0; i < boostSize; i++) {
            pool.ReleaseObject(objects[i]);
            Console.WriteLine(String.Format("Thread {0} released object {1}.", 
              Thread.CurrentThread.ManagedThreadId, objects[i].Id));
          }
        }
        else {
          // single
          PoolableObject poolableObject = pool.GetObject( );
          Console.WriteLine(String.Format("Thread {0} allocated object {1}.", 
            Thread.CurrentThread.ManagedThreadId, poolableObject.Id));
          poolableObject.DoWork( );
          Thread.Sleep(random.Next(0, 5000));
          pool.ReleaseObject(poolableObject);
          Console.WriteLine(String.Format("Thread {0} released object {1}.", 
            Thread.CurrentThread.ManagedThreadId, poolableObject.Id));
        }
      }
    }

    #region IObjectFactory<PoolableObject> Members
    PoolableObject IObjectFactory<PoolableObject>.CreateObject( ) {
        return new PoolableObject( );
    }
    #endregion
  }

  public class PoolableObject {
    public PoolableObject( ) {
      id = Guid.NewGuid( );
      Console.WriteLine(String.Format("Poolable object {0} is being constructed.", id));
    }

    ~PoolableObject( ) {
      Console.WriteLine(String.Format("Poolable object {0} is being destructed.", id));
    }

    private Guid id;
    public Guid Id {
      get {
        return id;
      }
    }

    int useCount;

    public void DoWork( ) {
      // Obviously this object should be able to actually do something, but
      // that's not relevant to the test program.
      // So we just count how many times an object has been used.
      Console.WriteLine(String.Format("Poolable object {0} has been used {1} times now.", id, ++useCount));
    }
  }

No feedback yet

Leave a comment


Your email address will not be revealed on this site.

Your URL will be displayed.
(Line breaks become <br />)
(Name, email & website)
(Allow users to contact you through a message form (your email will not be revealed.)
Please complete the song title below. Hint: enter 'h', 'e', 'a', 'v', 'e', 'n'
antispam test

Enter your email address:

Search

Oliver
MVP logo
March 2010
Sun Mon Tue Wed Thu Fri Sat
 << <   > >>
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31