在嵌套的 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 的初始值设定项之外的结果。这使您可以在 columnTasks
、await
中收集所有这些结果,然后创建新的 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);
我正在尝试等待另一个 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 的初始值设定项之外的结果。这使您可以在 columnTasks
、await
中收集所有这些结果,然后创建新的 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);