需要保留某个执行顺序时运行一堆异步任务

时间:2016-02-25 16:30:04

标签: c# .net async-await

我正在尝试将原始代码异步化

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

工作正常:

    var tasks = new List<Task>();

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

    await Task.WhenAll(tasks);

但是,在我保存并将项目添加到我的数据库之前,我需要添加一个额外的清理调用:

   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);

上面的代码不正确,因为在相应的DeleteAsync完成之前不应执行SaveAsync。换句话说,删除必须始终在为每个项目保存之前进行,但项目的顺序无关紧要。

有完美的方法吗?

3 个答案:

答案 0 :(得分:6)

创建一个async方法,对单个项目执行删除,然后执行保存,并对每个项目并行执行所有这些复合操作:

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

答案 1 :(得分:2)

您可以使用Func<Task>将两个异步调用封装到单个Task中,如下所示:

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());
}

这将创建一个调用delete方法的Task,异步等待它,然后调用save方法并异步等待它。

您可以使用方法执行相同的操作。

答案 2 :(得分:1)

如何使用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);