Skip to content

Example IdGenerator Usage and ThreadPool Tests

piranout edited this page Jun 30, 2015 · 1 revision

Self-contained Performance Test and Example Code

This is a complete program that will:

  • Show how to use the Id Generator
  • Test it for performance
  • Verify thread safety
  • Ensure Ids are collision-free.

Just add the NuGet Package, paste the entire class below into the Program.cs of a new console app, and run it.

using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Funcular.IdGenerators.Base36;

namespace ConsoleApplication1
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            TestDefaultConstructor();
            TestSpecificConstructor();
            TestMultithreading(seconds: 10);
            Console.Write("Press any key to exit. ");
            Console.ReadKey(true);
        }

        private static void TestDefaultConstructor()
        {
            var generator = new Base36IdGenerator();
            Console.WriteLine("Id from default constructor: {0}", generator.NewId());
            Console.WriteLine("Delimited Id from same: {0}", generator.NewId(true));
            Console.WriteLine();
        }

        private static void TestSpecificConstructor()
        {
            var generator = new Base36IdGenerator(12, 6, 7, "", "-", new[] {20, 15, 10, 5});
            Console.WriteLine("Id from 25-char constructor: {0}", generator.NewId());
            Console.WriteLine("Delimited Id from same: {0}", generator.NewId(true));
            Console.WriteLine();
        }

        private static void TestMultithreading(int seconds = 10)
        {
            var ids = new ConcurrentDictionary<string, string>();
            var threadIds = new ConcurrentDictionary<int, int>();
            var tokenSource = new CancellationTokenSource();
            Console.WriteLine("Starting collision, thread safety and performance test.");
            Stopwatch sw = Stopwatch.StartNew();
            for (int i = 0; i < 10; i++)
            {
                ThreadPool.QueueUserWorkItem(state => MakeIdsUntilCancel(ids, threadIds, tokenSource));
            }
            
            while (sw.Elapsed.Seconds < seconds)
            {
                Console.Write(".");
                Thread.Sleep(250);
            }
            tokenSource.Cancel();
            Console.WriteLine();
            Console.WriteLine(
                "Thread pool produced {0:n0} ids using {1} threads in {2}\r\n({3:n0}/sec) with no collisions. Id length is {4}.", 
                ids.Count, 
                threadIds.Count, 
                sw.Elapsed,
                ((double)ids.Count / (double)sw.ElapsedMilliseconds) * 1000,
                ids.First().Key.Length);
            Console.WriteLine();
        }

        private static void MakeIdsUntilCancel(ConcurrentDictionary<string, string> ids, ConcurrentDictionary<int, int> threadIds, CancellationTokenSource tokenSource)
        {
            var generator = new Base36IdGenerator();
            while (tokenSource.IsCancellationRequested == false)
            {
                if (!ids.TryAdd(generator.NewId(), ""))
                    throw new Exception(string.Format("Id collision after {0:n0} Ids!", ids.Count));
                threadIds.TryAdd(Thread.CurrentThread.ManagedThreadId, 0);
            }
        }
    }
}

Clone this wiki locally