Skip to content

Instantly share code, notes, and snippets.

@Ariex
Created August 15, 2018 23:33
Show Gist options
  • Save Ariex/c8e0cc246bf2150b61fc6cc14aea8db7 to your computer and use it in GitHub Desktop.
Save Ariex/c8e0cc246bf2150b61fc6cc14aea8db7 to your computer and use it in GitHub Desktop.
An object pool with size fixed
public class FixSizedObjectPool<T>
{
protected Func<T> Generator;
protected ConcurrentBag<T> ObjectBag;
protected int MaxSize;
protected long createdInstanceCount = 0;
protected SemaphoreSlim Pool;
public FixSizedObjectPool(Func<T> objectGenerator, int maxSize)
{
this.Generator = objectGenerator;
this.MaxSize = maxSize;
this.Pool = new SemaphoreSlim(0, maxSize);
this.ObjectBag = new ConcurrentBag<T>();
}
public async Task<T> GetObject()
{
T item;
if (Interlocked.Increment(ref createdInstanceCount) <= MaxSize)
{
return this.Generator();
}
else
{
Interlocked.Decrement(ref createdInstanceCount);
await Pool.WaitAsync();
if (this.ObjectBag.TryTake(out item))
{
return item;
}
else
{
return await GetObject();
}
}
}
public void PutObject(T obj)
{
this.ObjectBag.Add(obj);
Pool.Release();
}
}
@Ariex
Copy link
Author

Ariex commented Aug 15, 2018

this is modified from: https://docs.microsoft.com/en-us/dotnet/standard/collections/thread-safe/how-to-create-an-object-pool, and tested with following code

using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

namespace ObjectPool
{
    class Program
    {
        static void Main(string[] args)
        {
            CancellationTokenSource cts = new CancellationTokenSource();

            // Create an opportunity for the user to cancel.
            Task.Run(() =>
            {
                if (Console.ReadKey().KeyChar == 'c' || Console.ReadKey().KeyChar == 'C')
                    cts.Cancel();
            });

            FixSizedObjectPool<MyClass> pool = new FixSizedObjectPool<MyClass>(() => new MyClass(), Environment.ProcessorCount);

            // Create a high demand for MyClass objects.
            var counter = 0L;
            Parallel.For(0, 1000000, (i, loopState) =>
            {
                MyClass mc = pool.GetObject().Result;
                // This is the bottleneck in our application. All threads in this loop
                // must serialize their access to the static Console class.
                var value = mc.GetValue(i);
                Console.WriteLine(Interlocked.Increment(ref counter).ToString() + "   " + value.ToString("{0:####.####}"));

                pool.PutObject(mc);
                if (cts.Token.IsCancellationRequested)
                    loopState.Stop();

            });
            Console.WriteLine("Press the Enter key to exit.");
            Console.ReadLine();
            cts.Dispose();
        }
    }
    class MyClass
    {
        public static int InstanceId = 0;
        public int[] Nums { get; set; }

        public int Id { get; set; }
        public double GetValue(long i)
        {
            //Console.WriteLine("Instance: " + this.Id);
            System.Threading.Thread.Sleep(new Random().Next(1000) + 1000);
            return Math.Sqrt(Nums[this.Id]);
        }
        public MyClass()
        {
            Id = InstanceId++;
            Nums = new int[1000000];
            //Console.WriteLine("Creating instance");
            Random rand = new Random();
            //System.Threading.Thread.Sleep(4000);
            for (int i = 0; i < Nums.Length; i++)
            {
                Nums[i] = rand.Next();
            }
        }
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment