I am running a Thread
which get called in a static interval.
In this Thread
I am running several Tasks
(20-200).
All this works fine, but when the Thread
gets called the first time, it takes like ~1 sec for one Tasks
to start.
As soon as the while
loop is in the second loop or when the Thread
stops, and gets called a second time, the problem is gone.
public static async void UpdateThread()
{
while(!stop)
{
foreach (DSDevice device in DSDevices)
{
var task = Task.Run(() =>
{
// Delay is measured here
// Do Stuff
});
}
//No Delay
await Task.WhenAll(tasks);
Thread.Sleep(Sleeptime);
}
}
CodePudding user response:
The Task.Run
runs the code on the ThreadPool
, and the ThreadPool
creates initially a limited number of threads on demand. You can increase this limit with the SetMinThreads
method:
ThreadPool.SetMinThreads(200, 200);
...but check out the documentation before doing so. Increasing this threshold is not something that you should do without thinking. Having too many ThreadPool
threads defeats the purpose of having a pool in the first place. Think whether it's better to have a dedicated thread per device, for the whole life-time of the program.
As a side note, if I was in your shoes I would not parallelize the processing of the devices by creating tasks manually. I would use the Parallel.ForEach
method, which exists for exactly this kind of job. As a bonus it allows to control the degree of parallelism, either to a specific number or to -1 for unlimited parallelism:
public static async Task MonitorDevicesPeriodicAsync(
CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
Task delayTask = Task.Delay(MonitorDevicesPeriodMilliseconds);
await Task.Run(() =>
{
ParallelOptions options = new() { MaxDegreeOfParallelism = -1 };
Parallel.ForEach(DSDevices, options, device =>
{
// Do Stuff with device
});
});
await delayTask;
}
}
The Parallel.ForEach
invokes also the delegate on the ThreadPool
(by default), and it can saturate it as easily as the await Task.WhenAll(tasks)
approach, so you might need to use the ThreadPool.SetMinThreads
method as well.
Three more off topic suggestions: prefer async Task
over async void
. Async void is intended for event handler only. Also use a CancellationToken
for stopping the while
loop instead of a non-volatile bool stop
field. In a multithreaded environment, it's not guaranteed that the mutation of the field from one thread will be visible from other threads. Alternatively declare the field as volatile
. Finally use the Task.Delay
instead of the Thread.Sleep
, create the Task.Delay
task at the start of the iteration and await
it at the end, for a stable periodic invocation.