Blendester
Blendester

Reputation: 1653

How to run multiple threads on ASP.NET MVC efficiently?

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

Answers (2)

Harsh
Harsh

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

Camilo Terevinto
Camilo Terevinto

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

Related Questions