在嵌套的LINQ-Select中使用Async / Await,而不必使用Task.WhenAll

时间:2019-01-02 13:46:46

标签: c# .net linq async-await task-parallel-library

我正在尝试在另一个选择语句内的一个选择语句内等待异步操作。

var result = someList
    .Select(table => new Table
    {
        Columns = table.Select(async column => new Column
        {
            Constraints = await GetColumnConstraints()
        })
    })
    .ToList();

此处的“问题”是嵌套的select语句返回任务列表。通常,我们将使用Task.WhenAll()等待所有任务。因此,最简单的方法是将列的类型从List<Column>更改为List<Task<Column>>,然后使用SelectMany()来获取每个Task并等待它们。但是我无法更改列的数据类型。

我该如何实现?我找不到任何不涉及Task.WhenAll()

的解决方案

2 个答案:

答案 0 :(得分:1)

显然SomelistTables的序列,其中每个Table都有Columns的序列。

在我看来,这些表的列不影响GetColumnConstraints()。为什么每列调用一次此函数?如果只调用一次,会不会更有效率?

var columnConstraints = await GetColumnConstraintsAsync();
var result = tables.Select(table => new Table
{
    Columns = table.Select(column => new Column
    {
        Constraints = columnConstraints,
        ...
    })
})
.ToList();

可能是您简化了问题,而枚举的表和列确实会影响所获取的约束,例如,因为它们被用作输入变量。也许,如果您第二次调用该函数,则会遇到不同的约束条件?

如果您确实需要获取每个表的每个列的约束,则在创建表之前先等待获取约束:

var result = tables.Select(table => 
{
    var columnTasks = table.Select(column => GetColumnContraintsAsync(...)).ToArray();
    // all tasks are running now, wait until all are completed:
    await Task.WhenAll(columnTasks);
    // fetch the result from every task:
    var columnTaskResults = columnTasks.Select(columnTask => columnTask.Result).ToList();

    // create a Table with these results and return it:
    return new Table
    {
        Columns = columnTaskResults,
    };
})
.ToList();

答案 1 :(得分:1)

您不需要更改Column的类型,只需要在表的初始值设定项之外await即可。这样一来,您就可以在columnTasksawait中收集所有结果,然后创建新表。

var result = someList.Select(async table =>
{
    var columnTasks = table.Select(async column => new Column()
    {
        Constraints = await GetColumnConstraints()
    });
    var columns = await Task.WhenAll(columnTasks);
    return new Table()
    {
        Columns = columns
    };
});

请注意,尽管async沿链条向上发展,所以reuslt现在是IEnumerable<Task<Table>>,您必须await Task.WhenAll才能获得{{ 1}}

Table