Thread Pooling in C#

Thread Pooling in C#

In this article, I am going to discuss Thread Pooling in C# with examples. Please read our previous article where we discussed the Performance Testing of a multithreaded application in C#. As part of this article, we are going to discuss the following pointers.

  1. The Request Life cycle of a Thread.
  2. What is Thread Pooling?
  3. Why do we need Thread Pooling in C#?
  4. Performance testing between normal thread and thread pooling
The Request Life cycle of a Thread in C#.

Let us understand the life cycle of a thread in C#. In order to understand this, please have a look at the following image. When the .NET framework receives a request (the request can be a method call or function call from any kind of application). To that handle request, a thread object is created. When the thread object is created some resources are allocated to that thread object such as memory. After then the task is executed and once the task is completed then the garbage collector removes that thread object for free-up memory allocation. This is the life cycle of a thread in C#.

Request Life cycle of a Thread in C#

These steps are going to be repeated again and again for each request that comes in a multithread application. That means every time a new thread object created and get allocated in the memory. If there are many requests then there will be many thread objects and if there are many thread objects then there will be load on the memory which slows down your application.

There is a great room for performance improvements. The Thread object is created, resources are allocated, the task is executed, and then it should not go for garbage collection, instead of how about taking the thread object and put it into a pool as shown in the below image. This is where thread pooling comes into the picture.

Thread Pooling in C#

Thread Pooling in C#:

Thread pool in C# is nothing but a collection of threads that can be reused to perform no of tasks in the background. Now when a request comes, then it directly goes to the thread pool and checks whether there are any free threads available or not. If available, then it takes the thread object from the thread pool and executes the task as shown in the below image.

Thread Pooling Life Cycle in C#

Once the thread completes its task then it again sent back to the thread pool so that it can reuse. This reusability avoids an application to create the number of threads and this enables less memory consumption.

How to use Thread Pooling in C#?

Let us see a simple example to understand how to use Thread Pooling. Once you understand how to use thread pooling then we will see the performance benchmark between the normal thread object and thread pool.

Step1:

In order to implement thread pooling in C#, first, we need to import the Threading namespace as ThreadPool class belongs to this namespace as shown below.

using System.Threading;

Step2:

Once you import the Threading namespace, then you need to use the ThreadPool class and using this class you need to call the QueueUserWorkItem static method. If you go to the definition of the QueueUserWorkItem method, then you will see that this method takes one parameter of type WaitCallback object. While creating the object of the WaitCallback class, you need to pass the method name that you want to execute.

ThreadPool.QueueUserWorkItem(new WaitCallback(MyMethod));

Here, the QueueUserWorkItem method Queues the function for execution and that function executes when a thread becomes available from the thread pool. If no thread is available then it will wait until one thread gets freed. Here MyMethod is the method that we want to execute by a thread pool thread.

The complete code is given below.

As you can see in the below code, here, we create one method that is MyMethod and as part of that method, we simply printing the thread id, whether the thread is a background thread or not and whether it is from thread pool or not. And we want to execute this method 10 times using the thread pool threads. So, here we use a simple for each loop and use the ThreadPool class and call that method.

using System;
using System.Threading;

namespace ThreadPoolApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 10; i++)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(MyMethod));
            }
            Console.Read();
        }

        public static void MyMethod(object obj)
        {
            Thread thread = Thread.CurrentThread;
            string message = $"Background: {thread.IsBackground}, Thread Pool: {thread.IsThreadPoolThread}, Thread ID: {thread.ManagedThreadId}";
            Console.WriteLine(message);
        }
    }
}

Once you execute the above code, it will give you the following output. As you can see, it shows that it is a background thread and this thread is from the thread pool and the thread Ids may vary in your output. Here, you can see three threads handle all the 10 method calls.

How to use Thread Pooling in C#?

Performance testing using and without using Thread Pool in C#:

Let us see an example to understand the performance benchmark. Here, we will compare how much time does the thread object takes and how much time does the thread pool thread takes to do the same task i.e. to execute the same methods.

In order to do this, what we are going to do is, we will create a method called Test as shown below. This method takes an input parameter of type object and as part of that Test method we are doing nothing means an empty method.

Performance testing using and without using Thread Pool in C#:

Then we will create two methods such as MethodWithThread and MethodWithThreadPool and inside these two methods, we will create one for loop which will execute 10 times. Within for loop, we are going to call the Test as shown below. As you can see, the MethodWithThread method uses the Thread object to call the Test method while the MethodWithThreadPool method uses the ThreadPool object to call the Test method.

Performance testing using and without using Thread Pool in C#:

Now we need to call the above two methods (MethodWithThread and MethodWithThreadPool) from the main method. As we are going to test the performance benchmark, so we are going to call these two methods between the stopwatch start and end as shown below. The Stopwatch class is available in System.Diagnostics namespace. The for loop within the Main method is for warm-up. This is because when we run the code for the first time, compilation happens and compilation takes some time and we don’t want to measure that.

Performance testing using and without using Thread Pool in C#:

The complete code is given below.
using System;
using System.Diagnostics;
using System.Threading;

namespace ThreadPoolApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 10; i++)
            {
                MethodWithThread();
                MethodWithThreadPool();
            }

            Stopwatch stopwatch = new Stopwatch();

            Console.WriteLine("Execution using Thread");
            stopwatch.Start();
            MethodWithThread();
            stopwatch.Stop();
            Console.WriteLine("Time consumed by MethodWithThread is : " +
                                 stopwatch.ElapsedTicks.ToString());
            
            stopwatch.Reset();

            Console.WriteLine("Execution using Thread Pool");
            stopwatch.Start();
            MethodWithThreadPool();
            stopwatch.Stop();
            Console.WriteLine("Time consumed by MethodWithThreadPool is : " +
                                 stopwatch.ElapsedTicks.ToString());
            
            Console.Read();
        }

        public static void MethodWithThread()
        {
            for (int i = 0; i < 10; i++)
            {
                Thread thread = new Thread(Test);
            }
        }

        public static void MethodWithThreadPool()
        {
            for (int i = 0; i < 10; i++)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(Test));
            }           
        }

        public static void Test(object obj)
        {
        }       
    }
}

Output:

Thread Pool in C#

As you can see in the above output, the Time consumed by MethodWithThread is 663 and the Time consumed by MethodWithThreadPool is 93. If you observe there is a vast time difference between these two.

So it proofs that the thread pool gives better performance as compared to the thread class object. If there are needs to create one or two threads then you need to use Thread class object while if there is a need to create more than 5 threads then you need to go for thread pool class in a multithreaded environment.

That’s it for today. In this article, I try to explain Thread Pooling in C# with some examples. I hope you understood thread pooling and enjoy this article.

Leave a Reply

Your email address will not be published. Required fields are marked *