AstroSharp
AstroSharp

Reputation: 1902

Run a bunch async tasks when a certain execution order needs to be preserved

I am trying to asynchronize my original code

for(var item in items)
{
    dbAccess.Save(item);
}

which works fine:

    var tasks = new List<Task>();

    for(var item in items) 
    { 
      tasks.Add(dbAccess.SaveAsync(item)); 
    }

    await Task.WhenAll(tasks);

However, I need to add an additional clean-up call before I save and item to my DB:

   var tasks = new List<Task>();

    for(var item in items) 
    { 
      tasks.Add(dbAccess.DeleteAsync(item.id)); 
      tasks.Add(dbAccess.SaveAsync(item)); 
    }

    await Task.WhenAll(tasks);

This code above is incorrect since SaveAsync should not be executed until the corresponding DeleteAsync is finished. In other words Deletion must always go before Saving for each item but the order for the items does not matter.

Is there a perfect way to do this ?

Upvotes: 9

Views: 9509

Answers (3)

Yacoub Massad
Yacoub Massad

Reputation: 27861

You can use a Func<Task> to encapsulate the two async calls into a single Task like this:

for(var item in items) 
{
    //We store the value of item in a local variable
    //because it is not recommended to close over a loop variable
    var my_item = item; 

    Func<Task> task_fact = async () =>
    {
        await dbAccess.DeleteAsync(my_item.id); 
        await dbAccess.SaveAsync(my_item); 
    };

    tasks.Add(task_fact());
}

This will create a Task that calls the delete method, asynchronously wait for it, and then calls the save method and asynchronously wait for it.

You can do the same thing using a method.

Upvotes: 3

Sean
Sean

Reputation: 62472

How about using ContinueWith:

var tasks = new List<Task>();

for(var item in items) 
{ 
  var task = dbAccess.DeleteAsync(item.id)
             .ContinueWith(antecedent => dbAccess.SaveAsync(item))
             .Unwrap();

  tasks.Add(task); 
}

await Task.WhenAll(tasks);

Upvotes: 2

Servy
Servy

Reputation: 203828

Create an async method that performs the delete, then the save, for a single item, and perform all of those composite operations on each item in parallel:

var tasks = items.Select(async item => 
{
    await dbAccess.DeleteAsync(item.id);
    await dbAccess.SaveAsync(item);
});
await Task.WhenAll(tasks);

Upvotes: 9

Related Questions