编写一个带有 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(核心)应用程序,您需要一个专门用于这些东西的线程池。
我正在研究代码性能优化,需要建议使用 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(核心)应用程序,您需要一个专门用于这些东西的线程池。