编写一个带有 Parallel.Foreach 循环的异步方法,它会调用另一个异步方法来拉取记录

Write an async method with Parallel.Foreach loop that does call another async method to pull record

我正在研究代码性能优化,需要建议使用 parallel.foreach 和/或 WhenAll.

实现 async 的最佳方法

代码分为三个主要区域。

Code Definition

MethodA 选择 Customer 列表

MethodB PartA 遍历客户并通过 Azure Function 从数据库中选择记录。这是 1:* 关系,因此 1 个客户可以有多个记录。

MethodB PartB 浏览在方法 B 部分 A 中选择的客户记录列表,并查看是否有任何附件。如果有文件/文件,则它处理并将“客户参考”发送回 'MethodA' 并将记录存储在字典中。然后发送

方法一

public async Task<List<Customers>> MethodA(){

  List<Customer> customers = await GetAllCustomers();
  var inboundCustomerFiles= new List<InboundCustomerFiles>(); 

   Parallel.ForEach(customer, async customer =>
   {
     var processedCustomer = await MethodB(customer);
     inboundCustomersFiles.AddRange(processedCustomer);

   });
}

方法 B

  public static async Task<List<InboundCustomerFiles>> MethodB(Customer customer){
     var customerRecord = await GetCustomerRecord(customerId);

     foreach(var customer in customerRecord){
        var files = await getCustomerRecordFile(customerRecordId)
        //...... remaining code
     }
    return inboundCustomerFiles;
  }

方法三

public static async Task<List<InboundCustomerFiles>> GetCustomerRecord(int customerId){
     //API call here that further pull `record` from database
return List<Records>();
}

方法 B customerRecord 中的过程需要时间。我如何确保它处理数据和 return 以更正 MethodA 中的客户线程。我曾尝试在 methodB 中使用,但速度变慢,而且我知道 Parallel.Foreach 不会等待,所以我尝试在 lambda 表达式中添加 async 引用,但不确定 A 是否正确或是否有效。

一方面,您可以假装 Parallel.ForEach 等待您的 async 函数,但实际上并没有。相反,你想写这样的东西:

   await Task.WhenAll(customers.Select(async customer =>
   {
     var processedCustomer = await MethodB(customer);
     inboundCustomersFiles.AddRange(processedCustomer);
   }));

Task.WhenAll 的行为类似于 Parallel.ForEach,但它是可等待的,它还会等待您传递给它的每个任务,然后再完成自己的任务。因此,当您的 await Task.WhenAll 完成时,所有内部任务也已完全完成。

the process in methodB customerRecord takes time

这很含糊。如果您的意思是它需要服务器 and/or IO 时间,那没关系,这就是 async 的用途。如果你的意思是它需要 你的 CPU 时间(即它在本地处理数据很长时间),那么你应该在线程池上启动一个任务并等待它完成。 请注意,这不一定是默认线程池!特别是如果您正在编写 ASP.NET(核心)应用程序,您需要一个专门用于这些东西的线程池。