0

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);  
1
  • Note that you should be somewhat wary of recursive async methods. It's probably worth transforming this method into being iterative, rather than recursive. Commented Jul 29, 2014 at 15:31

1 Answer 1

7

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);
}
Sign up to request clarification or add additional context in comments.

8 Comments

thanks. Question is, do I need to make DoSomething and DoWork as Async? Could I keep them as regular sync methods and follow Selman22's or Castro's answer, and still get the full benefit of parallel processing?
@Prabhu: You stated in a comment that you get the "compiler warning saying I am not using the await keyword for DoSomething and DoWork". So I infer they're already asynchronous; I just renamed them to follow the naming convention.
Sure. But DoSomething and DoWork are my methods, so I am able to make then non-async if it will make things simpler. Is there a benefit of keeping them async?
They should be asynchronous if they have asynchronous work to do (usually I/O). They should be synchronous if they have synchronous work to do (usually CPU computation). Let the operation determine how the method looks; don't force the method to be a certain way, imposing a mismatching signature onto the operation.
do you see a potential problem with DoWorkAsync being recursive?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.