Cuthbert
Cuthbert

Reputation: 1322

Determine number of threads waiting in threadpool in C#

Is it possible to see how many threads are waiting to execute in the queue of the Threadpool?

If I do this:

for (int i = 0; i < 5000; i++)
{
    tasks.Add(Task.Run(() => { TaskTest(); }));
}
Task.WaitAll(tasks.ToArray());

Inside TaskTest, I do some work that typically takes ~500ms, I also update a variable with the highest number of threads seen:

ThreadPool.GetMaxThreads(out maxthreads, out completionthreads);
ThreadPool.GetAvailableThreads(out availablethreads, out completionthreads);

int threads_in_use = maxthreads - availablethreads;
mHighwaterThreads = Math.Max(mHighwaterThreads, threads_in_use);

Max threads, for my computer, is usually above 32000. mHighwaterThreads is usually around 75.

I would like to know if there is a way to see how many threads are waiting to execute in the Threadpool.

Upvotes: 7

Views: 6719

Answers (3)

Elo
Elo

Reputation: 2362

I used a simple method to know how many Task.Run are awaiting ThreadPool execution, by incrementing a counter at the moment I call Task.Run and decrementing it at the moment the code really executes :

long waitingTaskCount = 0; // Current number of Tasks waiting for execution
long executedTasksCount = 0; // Total number of executed Tasks
long totalWaitingTimeMs = 0; // Total waiting time in ms

void ExecutingMethod()
{
    Interlocked.Increment(ref waitingTaskCount);
    Stopwatch swTaskWaitingTime = Stopwatch.StartNew();
    Task.Run(() =>
    {
        Interlocked.Decrement(ref waitingTaskCount);
        Interlocked.Increment(ref executedTasksCount); 
        Interlocked.Add(ref totalWaitingTimeMs ,swTaskWaitingTime.ElapsedMilliseconds;    
        // (...)
    };
}

And I also added a waiting time counter and a tasks execution count.

  • So to obtain mean waiting time in milliseconds, just compute totalWaitingTimeMs / executedTasksCount
  • You have the currently waiting tasks in waitingTaskCount

Upvotes: 1

Darragh
Darragh

Reputation: 2656

There is a ThreadPool.PendingWorkItemCount property.

https://learn.microsoft.com/en-us/dotnet/api/system.threading.threadpool.pendingworkitemcount?view=netcore-3.1

Another possibility if you're running .net core, is to run dotnet counters monitor --process-id 123

This will give you a console display of some runtime metrics. I believe the metric you're asking about is 3rd from the bottom.

Press p to pause, r to resume, q to quit.
    Status: Running

[System.Runtime]
    % Time in GC since last GC (%)                         0
    Allocation Rate / 1 sec (B)                       66,480
    CPU Usage (%)                                          0
    Exception Count / 1 sec                                0
    GC Heap Size (MB)                                    234
    Gen 0 GC Count / 60 sec                                0
    Gen 0 Size (B)                               200,991,744
    Gen 1 GC Count / 60 sec                                0
    Gen 1 Size (B)                                   385,440
    Gen 2 GC Count / 60 sec                                0
    Gen 2 Size (B)                               210,807,272
    LOH Size (B)                                  74,140,000
    Monitor Lock Contention Count / 1 sec                  0
    Number of Active Timers                              314
    Number of Assemblies Loaded                          272
    ThreadPool Completed Work Item Count / 1 sec          38
    ThreadPool Queue Length                                0
    ThreadPool Thread Count                                9
    Working Set (MB)                                     242

Some useful links:

https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-counters https://www.youtube.com/watch?v=jn54CjePzs0

Upvotes: 7

Elo
Elo

Reputation: 2362

I haven't found a way to obtain the count of Tasks waiting for execution in ThreadPool.

But I found a way to Monitor ThreadPool health:

I create a single global Timer (let's say every 5 seconds) and I measure the delay from the previous "Elapsed": as Microsoft .NET Timers are executed in ThreadPool, if delay is abnormal, for example 7 seconds, I know the Elapsed has had to wait a lot, so the ThreadPool was saturated.

Upvotes: 6

Related Questions