Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ThreadPool behaviour: not growing from minimum size

I had set up my thread pool like this:

ThreadPool.SetMaxThreads(10000, 10000);
ThreadPool.SetMinThreads(20, 20);

However, my app started hanging under heavy load. This seemed to be because worker tasks were not executing: I had used ThreadPool.QueueUserWorkItem to run some tasks which in turn used the same method to queue further work. This is obviously dangerous with a limited thread pool (a deadlock situation), but I am using a thread pool not to limit maximum threads but to reduce thread creation overhead.

I can see the potential trap there, but I believed that setting a maximum of 10000 threads on the pool would mean that if an item was queued, all threads were busy, and there weren't 10000 threads in the pool, a new one would be created and the task processed there.

However, I changed to this:

ThreadPool.SetMaxThreads(10000, 10000);
ThreadPool.SetMinThreads(200, 200);

..and the app started working. If that made it start working, am I missing something about how/when the thread pool expands from minimum toward maximum size?

like image 436
Kieren Johnstone Avatar asked Jan 26 '26 12:01

Kieren Johnstone


2 Answers

Whenever you use the thread pool, you are at the mercy of its "thread injection and retirement algorithm".

The algorithm is not properly documented ( that I know of ) and not configurable.

If you're using Tasks, you can write your own Task Scheduler

like image 91
Nick Butler Avatar answered Jan 29 '26 01:01

Nick Butler


The job of the threadpool scheduler is to ensure there are no more executing TP threads than cpu cores. The default minimum is equal to the number of cores. A happy number since that minimizes the overhead due to thread context switching. Twice a second, the scheduler steps in and allows another thread to execute if the existing ones haven't completed.

It will therefore take a hour and twenty minutes of having threads that don't complete to get to your new maximum. It is fairly unlikely to ever get there, a 32-bit machine will keel over when 2000 threads have consumed all available virtual memory. You'd have a shot at it on a 64-bit operating system with a very large paging file. Lots of RAM required to avoid paging death, you'd need at least 12 gigabytes.

The generic diagnostic is that you are using TP threads inappropriately. They take too long, usually caused by blocking on I/O. A regular Thread is the proper choice for those kind of jobs. That's probably hard to fix right now, especially since you're happy with what you got. Raising the minimum is indeed a quick workaround. You'll have to hand-tune it since the TP scheduler can't do a reasonable job anymore.

like image 41
Hans Passant Avatar answered Jan 29 '26 02:01

Hans Passant



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!