Freigeben über


Warming a Cold Pool

The thread pool for asynchronous IO threads attempts to automatically regulate the number of idle threads to balance the resource consumption of threads with the responsiveness of servicing tasks. When there is not much work to be done, idle threads are spun down. When a surge of work comes in, new threads are spun up. There are limits on the minimum number of threads, maximum number of threads, the rate at which threads are created, and so on to smooth out this behavior.

The minimum number of threads exists to allow the system to carry some idle capacity. Tasks ordinarily run on the CPU for only a short time after the IO operation completes so the near-term capacity of the system is roughly the number of truly idle threads plus the number of currently-working threads. However, if the system goes idle except for a few very long running tasks, then those long running tasks may occupy the minimum number of threads without actually providing any idle capacity. For example, WCF has a timer system that runs on an IO thread for a long period of time.

If there are no excess threads and it's unlikely for a long running task to complete at the right moment for a thread to be reused, then this causes the same performance problems as a cold start. Running a dummy task is a way to keep the thread pool warm in excess of the minimum number of threads by generating currently-working threads that are available for reuse essentially immediately.

 Overlapped o = new Overlapped();
NativeOverlapped* po = null;
IOCompletionCallback c = (x, y, z) =>
{
    Overlapped.Unpack(po);
    Overlapped.Free(po);
};
po = o.Pack(c, null);
ThreadPool.UnsafeQueueNativeOverlapped(po);

The use of a dummy task is an example of altering a heuristic behavior when you've got better predictive knowledge than available to the heuristic. This can be dangerous though if you don't review what's been done when the heuristic changes or your prediction stops being accurate.