Reputation: 1653
I've a scheduled task in my ASP.NET MVC
site that nightly sends notifications for the users.
I've been sending and awaiting notifications one by one, but it's taking an hour to complete now, so I thought I should send them in batches.
int counter = 0;
List<Task> tasks = new List<Task>();
foreach (var user in users)
{
tasks.Add(Task.Run(async () =>
{
await user.SendNotificationAsync();
counter++;
}));
if (tasks.Count >= 20)
{
await Task.WhenAll(tasks);
tasks.Clear();
}
}
if(tasks.Any())
{
await Task.WhenAll(tasks);
tasks.Clear();
}
But I've read that creating multiple threads is not efficient on the servers. How should I run multiple instances of the method on the server?
Upvotes: 0
Views: 1962
Reputation: 459
Just to shed light on what Camilo meant by his example was that, in your example, you were creating a new Task
to monitor your awaitable task. So, essentially, you were not only creating twice the number of tasks needed, you were also chaining them up - a Task
to monitor a Task
, where the middle task is just a proxy which will be picked up from the Threadpool just to monitor another task from the Threadpool.
As the user.SendNotificationAsync()
is an awaitable task anyway, you can directly add it to the List<Task>
- tasks and await
directly on it.
Hence his example.
Upvotes: 1
Reputation: 32072
Because you are not following the best practices on TPL, here's a rewrite on how you should do it:
List<Task> tasks = new List<Task>();
int counter = 0; // not sure what this is for
foreach (var user in users)
{
tasks.Add(user.SendNotificationAsync()); // do not create a wrapping task
counter++; // not sure about this either
// it won't ever be greater than 20
if (tasks.Count == 20)
{
await Task.WhenAll(tasks);
tasks.Clear();
}
}
if (tasks.Any())
{
await Task.WhenAll(tasks);
tasks.Clear();
}
This is perfectly fine, also, because threads will be spawned and destroyed as soon as they are done.
Upvotes: 3