Knowing how thread injection works in .Net is key to allowing your ASP.Net application to make the best use of system resources Credit: Thinkstock In the .Net Framework, the CLR is responsible for meting out resources to running applications. In particular, the CLR thread pool determines when threads are to be added or taken away. Understanding how this works will help you determine how to configure your ASP.Net application for optimal performance. The CLR thread pool contains two kinds of threads—the worker threads and the I/O completion port or IOCP threads. That means your ASP.Net worker process actually contains two thread pools: the worker thread pool and the IOCP thread pool. Naturally, these pools have different purposes. When you use methods like Task.Run, TaskFactory.StartNew, and ThreadPool.QueueUserWorkItem, the runtime takes advantage of worker threads for processing. When you make asynchronous I/O calls in your application, or your application accesses the file system, databases, web services, etc., then the runtime uses IOCP threads. Note too that each application domain has its own thread pool. Let’s take a closer look at how these threads are created and removed in the .Net Framework. Thread injection strategies The .Net thread pool starts injecting new threads whenever the number of busy threads becomes equal to the number of configured minimum threads in the thread pool. The default value of the minimum setting, which is the minimum number of both worker and IOCP threads, is determined by the number of processors in your system. Hence, if your system has four cores, you would have four worker threads and four IOCP threads by default. The .Net thread pool then injects additional worker threads on demand if existing threads are utilized and there is still work to be done. By the same token, if the demand for resources falls, the thread pool will begin taking threads away. Executing the following code snippet would display the number of logical processors in your system and the minimum number of worker and IOCP threads available. static void Main(string[] args) { int minimumWorkerThreadCount, minimumIOCThreadCount; int logicalProcessorCount = System.Environment.ProcessorCount; ThreadPool.GetMinThreads(out minimumWorkerThreadCount, out minimumIOCThreadCount); Console.WriteLine(“No. of processors: “ + logicalProcessorCount); Console.WriteLine(“Minimum no. of Worker threads: “ + minimumWorkerThreadCount); Console.WriteLine(“Minimum no. of IOCP threads: “ + minimumIOCThreadCount); Console.Read(); } The .Net thread pool manages threads using its built-in heuristics. The strategies adopted include starvation avoidance and a hill-climbing algorithm. In the former case, the .Net thread pool continues to add worker threads if there is no visible progress on the queued items. In the latter case, the .Net thread pool tries to maximize the throughput using as few threads as possible. The .Net thread pool injects or removes threads at intervals of 500 milliseconds or as a thread becomes free, whichever comes first. Now, based on the feedback available to the runtime, the .Net thread pool either removes threads or adds threads to maximize the throughput. If adding a thread does not increase throughput, it takes a thread away. This is the CLR’s hill-climbing technique in action. Now suppose you are running your ASP.Net application on IIS and your web server has a total of four CPUs. Assume that at any given point in time, there are 24 requests to be processed. By default the runtime would create four threads, which would be available to service the first four requests. Because no additional threads will be added until 500 milliseconds have elapsed, the other 20 requests will have to wait in the queue. After 500 milliseconds have passed, a new thread is created. As you can see, it will take many 500ms intervals to catch up with the workload. This is a good reason for using asynchronous programming. With async programming, threads aren’t blocked while requests are being handled, so the four threads would be freed up almost immediately. Recommended thread settings Given the way the .Net thread pool works and what we have discussed thus far, it is strongly recommended that you change the minimum configuration value—the default value—for both worker and IOCP threads. To do this in ASP.Net, you should change the minWorkerThreads and minIoThreads configuration settings under the <processModel> configuration element in the machine.config file in your system. <configuration> <system.web> <processModel minWorkerThreads=”provide your desired value here” minIoThreads=”provide your desired value here” /> </system.web> </configuration> You can set the minimum configuration values for both worker and IOCP threads to any value between one and 50. A good approach is to take a user mode process dump of the IIS worker process (W3wp.exe) and then use the !threadpool command to report the total number of worker threads. Once you know this value, simply divide it by the number of processor cores on your system to determine the minimum worker and IOCP thread settings. For example, if the total count of worker threads is 100 and you have four processors in your system, you can set the minimum values for both worker and IOCP threads to 25. To change the default minimum thread settings outside of ASP.Net, you can use the ThreadPool.SetMinThreads() method. With the goal of better thread management and improved performance, the CLR thread pool has been improved with each version of the CLR. As an example, with .Net Framework 4, the CLR gained thread stealing algorithms and support for concurrency and parallelism. With each new version of the CLR, the .Net thread pool is getting smarter about optimizing the throughput by creating and destroying threads as needed. In the meantime, you’ll want to experiment with different minimum thread settings to get the best performance from your .Net application. Related content how-to How to use FastEndpoints in ASP.NET Core Take advantage of the free open-source FastEndpoints library to build fast and lean APIs in your ASP.NET Core applications. By Joydip Kanjilal Jul 11, 2024 7 mins Microsoft .NET C# Development Libraries and Frameworks how-to How to use Refit to consume APIs in ASP.NET Core Take advantage of Refit REST library to simplify API consumption and make your code cleaner, more efficient, and easier to maintain. By Joydip Kanjilal Jul 04, 2024 10 mins C# Microsoft .NET Software Deployment how-to When to use an abstract class vs. interface in C# Understanding the differences between an abstract class and interface is key to designing loosely coupled and extensible applications. By Joydip Kanjilal Jun 20, 2024 10 mins Small and Medium Business Microsoft .NET C# how-to 6 security best practices for ASP.NET Core Learn the best practices and built-in safeguards for preventing attacks and protecting sensitive data in your ASP.NET Core web applications. By Joydip Kanjilal Jun 07, 2024 6 mins C# Microsoft .NET Web Development Resources Videos