在Select linq查询中使用async/await

Ari*_*her 1 c# linq select asynchronous async-await

阅读本文后: 在Parallel.ForEach中嵌套等待

我试着做以下事情:

private static async void Solution3UsingLinq()
{
    var ids = new List<string>() { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" };

    var customerTasks = ids.Select(async i =>
    {
        ICustomerRepo repo = new CustomerRepo();
        var id = await repo.getCustomer(i);
        Console.WriteLine(id);

    });
}
Run Code Online (Sandbox Code Playgroud)

出于某种原因,这不起作用......我不明白为什么,我认为有一个僵局,但我不确定......

spe*_*der 6

因此,在你的方法结束时,customerTasks包含IEnumerable<Task>的是还没有被列举.Select偶数内的代码都没有运行.

在创建这样的任务时,立即实现序列可能更安全,以降低双重枚举的风险(并偶然创建第二批任务).您可以通过调用ToList序列来完成此操作.

所以:

var customerTasks = ids.Select(async i =>
{
    ICustomerRepo repo = new CustomerRepo();
    var id = await repo.getCustomer(i); //consider changing to GetCustomerAsync
    Console.WriteLine(id);

}).ToList();
Run Code Online (Sandbox Code Playgroud)

现在......如何处理你的任务列表?你需要等待他们全部完成......

你可以这样做Task.WhenAll:

await Task.WhenAll(customerTasks);
Run Code Online (Sandbox Code Playgroud)

你可以通过asyncSelect语句中实际从委托中返回一个值来更进一步,所以你最终会得到一个IEnumerable<Task<Customer>>.

然后你可以使用不同的重载Task.WhenAll:

IEnumerable<Task<Customer>> customerTasks = ids.Select(async i =>
{
    ICustomerRepo repo = new CustomerRepo();
    var c = await repo.getCustomer(i); //consider changing to GetCustomerAsync
    return c;

}).ToList();

Customer[] customers = await Task.WhenAll(customerTasks); //look... all the customers
Run Code Online (Sandbox Code Playgroud)

当然,可能有更有效的方法可以一次性获得几个客户,但这可能是一个不同的问题.

相反,如果您希望按顺序执行异步任务:

var customerTasks = ids.Select(async i =>
{
    ICustomerRepo repo = new CustomerRepo();
    var id = await repo.getCustomer(i); //consider changing to GetCustomerAsync
    Console.WriteLine(id);

});
foreach(var task in customerTasks) //items in sequence will be materialized one-by-one
{
    await task;
}
Run Code Online (Sandbox Code Playgroud)

  • 执行“ToList”将并行执行它们,这可能不是我们的初衷。另外,对于您的第二个查询,在这种情况下不需要异步选择,只需返回“getCustomer”的结果 (2认同)