Prabhu
Prabhu

Reputation: 13325

Converting a Parallel.ForEach loop into parallel tasks using lambda expression

Need help converting this to a lamdba expression where I can use Task.WhenAll:

public void DoWork(string id)
{            
       var items = GetItems(id);  //takes time

       if (items == null)
       {
            return;
       }

       Parallel.ForEach(items, item =>
       {
            DoSomething(item); //takes time
            DoWork(item.subItemId);                    
       });           
}

I would like to change the Parallel For loop into tasks using a lambda expressions as suggested in Martin's answer in this thread: How to call an async method from within a loop without awaiting?

Not sure how to specify the multiple line after item =>. This doesn't seem to work:

public void DoWork(string id)
{            
       var items = GetItems(id);  //takes time

       if (items == null)
       {
           return;
       } 

       var tasks = items.Select(item => 
       {
           DoSomething(item)
           DoWork(item.subItemId)
       });      

       await Task.WhenAll(tasks);         
}

UPDATE:

Thank you all for your answers. If I have an if condition, would I be wasting tasks? Is there a better to code this? Do I need to be using Where instead?

var tasks = items.Select(async item => 
{ 
    if (item.HasWork)
    {
       await DoSomethingAsync(item);
       await DoWorkAsync(item.subItemId);
    }
});      

await Task.WhenAll(tasks);  

Upvotes: 0

Views: 1749

Answers (1)

Stephen Cleary
Stephen Cleary

Reputation: 456342

It's easiest to use an async lambda:

public async Task DoWorkAsync(string id)
{            
  var items = GetItems(id);  //takes time

  if (items == null)
    return;

  var tasks = items.Select(async item => 
  { 
    await DoSomethingAsync(item);
    await DoWorkAsync(item.subItemId);
  });      

  await Task.WhenAll(tasks);         
}

Martin's original answer assumes you'd write your own async method instead of an async lambda, which may make the code clearer:

public async Task DoWorkAsync(string id)
{            
  var items = GetItems(id);  //takes time

  if (items == null)
    return;

  var tasks = items.Select(item => ProcessAsync(item));

  await Task.WhenAll(tasks);         
}

private async Task ProcessAsync(T item)
{
  await DoSomethingAsync(item);
  await DoWorkAsync(item.subItemId);
}

Upvotes: 7

Related Questions