异步&在循环中等待多个任务,如何返回单个Task

时间:2013-12-11 18:36:31

标签: loops task-parallel-library async-await c#-5.0 entity-framework-6

此示例与实体框架有关,但问题更多的是如何在循环中await多个async任务。假设我在自定义DbContext类上有以下方法:

public async Task DiscardChangesAsync()
{
    foreach (var entry in ChangeTracker.Entries().Where(x => x != null))
    {
        switch (entry.State)
        {
            case EntityState.Added:
                entry.State = EntityState.Detached;
                break;
            case EntityState.Modified:
                entry.State = EntityState.Unchanged;
                break;
            case EntityState.Deleted:
                await entry.ReloadAsync(); // <-- only async method
                break;
        }
    }
}

以上编译并运行,但我不确定它的效率如何。例如,如果上下文包含10个已删除的实体条目,则线程会在继续循环之前停止并等待每个ReloadAsync,对吗?有没有办法让循环执行继续,并返回一个新的Task,直到所有10个ReloadAsync调用完成后才会完成?

1 个答案:

答案 0 :(得分:4)

严格回答你的问题:

public Task DiscardChangesAsync()
{
    List<Task> tasks = new List<Task>();
    foreach (var entry in ChangeTracker.Entries().Where(x => x != null))
    {
        switch (entry.State)
        {
            case EntityState.Added:
                entry.State = EntityState.Detached;
                break;
            case EntityState.Modified:
                entry.State = EntityState.Unchanged;
                break;
            case EntityState.Deleted:
                tasks.Add(entry.ReloadAsync());
                break;
        }
    }

    return Task.WhenAll(tasks);
}
但是,为了让EF能够同时重新加载所有这些内容,可能会更有效率:

public Task DiscardChangesAsync()
{
    List<DbEntityEntry> deleted = new List<DbEntityEntry>();

    foreach (var entry in ChangeTracker.Entries().Where(x => x != null))
    {
        switch (entry.State)
        {
            case EntityState.Added:
                entry.State = EntityState.Detached;
                break;
            case EntityState.Modified:
                entry.State = EntityState.Unchanged;
                break;
            case EntityState.Deleted:
                deleted.Add(entry);
                break;
        }
    }

    return ctx.RefreshAsync(RefreshMode.StoreWins, deleted);
}