Sunday, June 21, 2009

ThreadPool.QueueUserWorkItem() could be very slow

ThreadPool.QueueUserWorkItem() could be very slow if callback being executed as a work item calls Thread.Sleep(). Consider the following example:



  1. using System;
  2. using System.Threading;
  3.  
  4. namespace Test
  5. {
  6.   class Program
  7.   {
  8.     const int waitTime = 10000;
  9.     static void Main(string[] args)
  10.     {
  11.       for (int i = 0; i < 10; i++ )
  12.         ThreadPool.QueueUserWorkItem( TestProc, i);
  13.       Console.ReadKey();
  14.     }
  15.  
  16.     static void TestProc(object stateInfo)
  17.     {
  18.       Console.WriteLine("Item number #{0} at {1}", (int)stateInfo, DateTime.Now);
  19.       Thread.Sleep(waitTime);
  20.     }
  21.   }
  22. }




The problem is that thread pool waits around 500 ms before allocating a new thread.
You may solve it by pre-specifying a minimal amount of threads in your application:
ThreadPool.SetMinThreads(20, 200);

3 comments:

Anonymous said...

I am not sure what you did is right. try this one.

class Program
{

const int waitTime = 10000;

static void Main(string[] args)
{
ManualResetEvent[] items = new ManualResetEvent[10];

for (int i = 0; i < 10; i++)
{
items.Add(new ManualResetEvent(false));
}
Console.Out.WriteLine(DateTime.Now.ToLongTimeString());

foreach(ManualResetEvent context in items)
{
ThreadPool.QueueUserWorkItem(TestProc, context);
}
foreach (ManualResetEvent context in items)
{
context.WaitOne();
}
Console.Out.WriteLine(DateTime.Now.ToLongTimeString());
}
static void TestProc(object stateInfo)
{
Console.WriteLine(DateTime.Now);
Thread.Sleep(waitTime);
((ManualResetEvent)stateInfo).Set();
}
}

Alex Pinsker said...

Tried it - same result - takes a time until you get into the thread function. It's just optimization of .NET. Use ThreadPool.SetMinThreads()

jadsadah said...

Thank you for the explanation Alex.
Best regards