【问题标题】:Async/Await Multiple Linq Statements异步/等待多个 Linq 语句
【发布时间】:2019-09-17 18:07:01
【问题描述】:

我有一个 API 控制器操作,它执行大约 10 个单独的 linq 查询,这些查询用于形成我需要发送回客户端的摘要对象。这些 linq 查询都是在相同的数据上执行的。有没有一种方法可以在这种情况下使用 async/await 以便一个 linq 语句不必阻止其他语句运行?如果是这样,编写该 async/await 代码的最有效方法是什么?

总结一下我的问题:

  1. 在这种情况下我有异步/等待的用例吗?
  2. 如果是这样,与其创建一堆独立的任务,然后将它们全部填充到 Task.WhenAll() 中,有没有更有效的方法来编写它,以便我以后可以轻松添加更多 linq 查询? (没什么太疯狂的,只是干净且可维护)。
[HttpGet]
public IActionResult GetInventoryDetails(string id)
{
    var inventory = _storeInventoryRepo.FindByCondition(s => s.Id = id)

    var uniqueProductCount = inventory.Select(x => x.ProductId).Distinct().ToList().Count

    var totalProductInventoryValue = inventory.Sum(x =>x.UnitPrice & x.TotalUnits)

    var cheapestProduct = inventory.OrderBy(x => x.unitPrice).Select(x => x.ProductId).First();

    var inventorydetails = new InventoryDetails
    {
       UniqueProductCount = uniqueProductCount,
       TotalProductInventoryValue = totalProductInventoryValue,
       CheapestProduct = cheapestProduct
    }

    Return Ok(inventoryDetails)
}

    public class ProductInventory
    {
        public string Id { get; set; }
        public string ProductId { get; set; }
        public int UnitPrice { get; set; }
        public double TotalUnits { get; set; }
    }

如何使用 async/await 来允许 uniqueProductCost、totalProductInventoryValue 和最便宜的产品在不等待完成的情况下执行?

【问题讨论】:

  • 你能添加一些代码吗?这些 LINQ 查询是针对数据库还是内存数据源?
  • @juunas 刚刚更新了它——这有帮助吗?
  • inventory的类型是什么?
  • @juunas 检查我的更新
  • 如果你想并行运行它们,那就是另外一个问题了。然后你需要多线程,而不是 async/await。

标签: c# .net asp.net-core async-await


【解决方案1】:

由于您使用的是IEnumerable<T> 而不是IQueriable<T>,因此您不能使用async-await

除非你使用Task.Run。但是就像在 ASP.NET 中使用 async-await 和真正的异步 API(如 I/O)一样,您会牺牲性能来换取可用性,使用 Task.Run 会牺牲可用性来换取性能。

如果你使用Select(x => x.ProductId).Distinct().Count(),你将比使用Select(x => x.ProductId).Distinct().ToList().Count分配更少的CPU,使用更少的CPU。

使用inventory.OrderBy(x => x.unitPrice).First().ProductId 代替inventory.OrderBy(x => x.unitPrice).Select(x => x.ProductId).First() 也是如此。

【讨论】:

  • 如果我需要获得 DISTINCT 产品,您将如何使用上述计数?
  • 我的错。我在考虑this,结果弄乱了答案。
【解决方案2】:

在这种情况下我有异步/等待的用例吗?

如果您确定要同时运行这些数据库请求。

请注意,许多数据库客户端仅限于每个连接一个查询 - 在 EF 术语中,这意味着您需要为每个查询提供单独的数据库上下文。这种额外的复杂性(和开销)可能值得也可能不值得;你必须自己确定。

如果是这样,与其创建一堆独立的任务,然后将它们全部填充到一个 Task.WhenAll() 中,有没有更有效的方法来编写它,以便我以后可以轻松地添加更多 linq 查询? (没什么太疯狂的,只是干净且可维护)。

Task.WhenAll 将是最干净的方法。你可以将List<Task> 传递给Task.WhenAll,如果这对你来说更干净的话。

此外,如 cmets 中所述,您希望使用 IQueryable<T> 而不是 IEnumerable<T>。与数据库的通信必须是异步的,并且发生在 LINQ 表达式的 end 处。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-02
    • 2016-05-02
    • 2013-04-27
    • 2015-05-22
    • 2023-01-20
    • 1970-01-01
    • 2018-11-06
    • 1970-01-01
    相关资源
    最近更新 更多