Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding await in foreach loop

I am trying to optimize this code to decrease the time taken to complete the forloop. In this case, CreateNotification() takes a long time and using async await does not improve performance as each asynchronous call is being awaited. I would like to use Task.WhenAll() to optimize the code. How can I do this?

foreach (var notification in notificationsInput.Notifications)
{
  try
  {
    var result = await CreateNotification(notification);
    notification.Result = result;          
  }
  catch (Exception exception)
  {
    notification.Result = null;
  }
  notifications.Add(notification);
}
like image 869
Ajit Goel Avatar asked Sep 06 '25 08:09

Ajit Goel


1 Answers

You can call Select on the collection whose elements you want to process in parallel, passing an asynchronous delegate to it. This asynchronous delegate would return a Task for each element that's processed, so you could then call Task.WhenAll on all these tasks. The pattern is like so:

var tasks = collection.Select(async (x) => await ProcessAsync(x));
await Task.WhenAll(tasks);

For your example:

var tasks = notificationsInput.Notifications.Select(async (notification) =>
{
    try
    {
        var result = await CreateNotification(notification);
        notification.Result = result;          
    }
    catch (Exception exception)
    {
        notification.Result = null;
    }
});
await Task.WhenAll(tasks);

This assumes that CreateNotification is thread-safe.

like image 96
Douglas Avatar answered Sep 09 '25 17:09

Douglas