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

Using Async/Await inside nested LINQ-Select without having to use Task.WhenAll

我正在尝试等待另一个 select 语句中的 select 语句中的异步操作。

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

这里的"problem"就是嵌套select语句returns的一个任务列表。通常我们会使用 Task.WhenAll() 来等待所有任务。因此,最简单的做法是将列的类型从 List<Column> 更改为 List<Task<Column>>,然后使用 SelectMany() 获取每个任务并等待它们。但是我无法更改 Columns 的数据类型。

我怎样才能实现这样的目标?我找不到任何不涉及 Task.WhenAll()

的解决方案

显然 Somelist 是一个 Tables 的序列,其中每个 Table 都有一个 Columns 的序列。

在我看来,这些 table 的列不会影响 GetColumnConstraints()。为什么每列调用一次此函数?只调用一次不是更高效吗?

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

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

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

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

您不需要更改 Column 的类型,您只需要 await table 的初始值设定项之外的结果。这使您可以在 columnTasksawait 中收集所有这些结果,然后创建新的 table.

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 才能获得最终的 collection 共 Table

var tables = await Task.WhenAll(result);