The application I am developing processes data in consumer threads from a Blocking collection when it is done processing the data (never any more than 1ms) it spins that processed data off into a new thread from the ThreadPool to be sent to my users and stored in the database.
I start a stopwatch just before I call ThreadPool.QueueUserWorkItem and stop it as one of the first things I do in the function called by ThreadPool.QueueUserWorkItem (any code before this has been clocked at less than 1ms).
The time this stopwatch is reporting is worrying me a little, the average time is 4ms (no problem there) but the max is upwards of 900ms, the least threads ever used is 1, the most used is ~60 and the average is ~40.
Although as long as the average stays the same it should not be a problem I would love to know why I get the occasional ~1sec wait for a thread when I normally have 900+ free.
Some example code that will run independently with sleeps replacing actual processing:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class Program
{
static int[] AvailableThreads;
static Stopwatch[] stopwatch;
static BlockingCollection<int> Queue;
static ManualResetEvent consumerEvent;
static ManualResetEvent alldone;
static bool disposed = false;
static void Main(string[] args)
{
int iterations = 10000;
stopwatch = new Stopwatch[iterations];
AvailableThreads = new int[iterations];
Queue = new BlockingCollection<int>();
consumerEvent = new ManualResetEvent(false);
alldone = new ManualResetEvent(false);
Thread processThread = new Thread(new ThreadStart(ProcessThread));
processThread.IsBackground = true;
processThread.Start();
int MaxThreads = 0;
int y = 0;
ThreadPool.GetMaxThreads(out MaxThreads, out y);
for (int i = 0; i < stopwatch.Length; i++)
{
Queue.Add(i);
consumerEvent.Set();
}
alldone.Reset();
alldone.WaitOne();
long av = 0;
long max = 0;
int threadsAv = 0;
int threadsMax = 0;
for (int i = 0; i < stopwatch.Length; i++)
{
long ms = stopwatch[i].ElapsedMilliseconds;
av += ms;
threadsAv += AvailableThreads[i];
if (max < ms) max = ms;
if (threadsMax < AvailableThreads[i]) threadsMax = AvailableThreads[i];
}
if(av != 0) av = av / stopwatch.Length;
if (threadsAv != 0) threadsAv = threadsAv / stopwatch.Length;
Console.WriteLine("Average Time: {0}, Max Time: {1}, Max Thread: {2}, Average Available Threads: {3}, Max Available Threads: {4}", av, max, MaxThreads, threadsAv, threadsMax);
Console.ReadLine();
disposed = true;
}
static void ProcessThread()
{
while (!disposed)
{
foreach (int i in Queue.GetConsumingEnumerable())
{
if (disposed) return;
// Proccess a bit of data here .....
stopwatch[i] = new Stopwatch();
stopwatch[i].Start();
int y = 0;
ThreadPool.GetAvailableThreads(out AvailableThreads[i], out y);
ThreadPool.QueueUserWorkItem(TransmitThread, i);
}
consumerEvent.Reset();
consumerEvent.WaitOne();
}
}
static void TransmitThread(object data)
{
int i = (int)data;
stopwatch[i].Stop();
//Fake some work.
Thread.Sleep(1);
if (i == stopwatch.Length - 1) alldone.Set();
}
}
}
Example output:
Average Time: 581, Max Time: 1126, Max Thread: 1023, Average Available Threads: 1015, Max Available Threads: 1023
Can anyone provide some insight on this?