如何正确调用 Parallel.ForEach 循环中的调用异步方法[重复]
Posted
技术标签:
【中文标题】如何正确调用 Parallel.ForEach 循环中的调用异步方法[重复]【英文标题】:how to call Call Async Methods in Parallel.ForEach loop properly [duplicate] 【发布时间】:2020-09-09 00:59:21 【问题描述】:如何正确调用 Parallel.ForEach 循环中的调用异步方法。billDataService.SaveBillDetail 和 GetProfileDetails 都是异步方法。数据保存在 MongoDB 中的 SaveBillDetail 中。
public async Task ConvertXMLFileToJSON()
try
if (Directory.Exists(_appSettings.DocumentsStorage))
int i = 1; //Test
bool exists = Directory.GetFiles(_appSettings.DocumentsStorage).Any(x => x.Equals(Path.Combine(_appSettings.DocumentsStorage, "Ready.txt"), StringComparison.OrdinalIgnoreCase)); //Need to check
if (exists)
Parallel.ForEach(System.IO.Directory.GetFiles(_appSettings.DocumentsStorage, "*.xml"), (currentFile) =>
try
XElement root = XElement.Load(currentFile); // or .Parse(string);
//Removing CDATA property from XElement.
XElement items = XElement.Parse(root.ToString().Replace("<![CDATA", "").Replace("]]>", "").Replace("[", ""));
//Removing XML_INFO Tag from XElement.
items.Elements("XML_INFO").Remove();
XmlDocument xmlDoc = new XmlDocument();
using (XmlReader xmlReader = items.CreateReader())
xmlDoc.Load(xmlReader);
var json = JsonConvert.SerializeXmlNode(xmlDoc);
billDetails obj = JsonConvert.DeserializeObject<billDetails>(json);
BillDetails billDetails = new BillDetails();
billDetails.AccountNumber = obj.BILL_INFO.BILL_RUN.ACCT_INFO.ACCT_CODE;
billDetails.MobileNumber = obj.BILL_INFO.BILL_RUN.ACCT_INFO.PRINCIPAL_NO.STR_PRINCIPAL_NO;
billDetails.BillDate = DateTime.ParseExact(obj.BILL_INFO.BILL_RUN.BILL_PROP.TO_DATE, "dd/MM/yyyy", CultureInfo.InvariantCulture);
billDetails.DueAmount = obj.BILL_INFO.BILL_RUN.ACCT_INFO.ACCT_BALANCE_TRACE.TOTAL_DUE;
billDetails.CustomerName = obj.BILL_INFO.BILL_RUN.CUST_INFO.CUST_NAME.FULL_NAME;
billDetails.InvoiceId = obj.BILL_INFO.BILL_RUN.BILL_PROP.INVOICE_ID;
billDetails.DueDate = DateTime.ParseExact(obj.BILL_INFO.BILL_RUN.BILL_PROP.DUE_DATE, "yyyyMMdd hh:mm:ss", CultureInfo.InvariantCulture);
billDetails.RepositoryName = "postpaid";
billDetails.BillRun = obj.BILL_INFO.BILL_RUN; //tempObj2.BILL_INFO.ToString().Remove(0, 1);
billDetails.ObjectId = Guid.NewGuid().ToString();
if (billDetails != null)
BillDataService billDataService = new BillDataService(_dbConfig);
Console.WriteLine("SaveBillDetail");
if (billDataService.SaveBillDetail(billDetails) != null)
Console.WriteLine("SaveBillDetail done");
GetProfileDetails(billDetails);
_logger?.LogInformation(i++ + " File Success");
Console.WriteLine(i++ + " File Success");
// File.Delete(file); //Delete File
catch (Exception ex)
_logger?.LogError(ex, "Error");
finally
);
catch (Exception ex)
_logger?.LogError(ex, "Error");
finally
public async Task GetProfileDetails(BillDetails billDetails)
try
ProfileService profileService = new ProfileService(_dbConfig);
var searchFilter = new SearchFilter
Filters = new List<Filter>()
;
if (!string.IsNullOrEmpty(billDetails.AccountNumber))
searchFilter.Filters.Add(new Filter() PropertyName = "AccountNumber", Operator = Operator.Equals, Value = billDetails.AccountNumber, CaseSensitive = true );
if (searchFilter != null)
Profile profile = await profileService.GetProfiles(searchFilter);
if (profile != null)
await SendMailNotification(profile, billDetails);
else
_logger?.LogError("Profile Info not found");
catch (Exception ex)
_logger?.LogError(ex, "Error");
throw;
finally
正常的每个循环我可以在 MongoDB.but Parallel.ForEach 循环中调用和保存数据调用方法前面的await。
【问题讨论】:
【参考方案1】:您可以将代码更改为如下所示,然后等待所有任务完成。
var fileTasks = System.IO.Directory.GetFiles(_appSettings.DocumentsStorage, "*.xml").Select(async currentFile =>
try
XElement root = XElement.Load(currentFile); // or .Parse(string);
// rest o your code here
if (billDetails != null)
if (billDataService.SaveBillDetail(billDetails) != null)
Console.WriteLine("SaveBillDetail done");
await GetProfileDetails(billDetails);
catch(exception ex) //log exeption
);
await Task.WhenAll(fileTasks);
【讨论】:
它正在工作,但没有变化。每个循环的性能与正常情况相比是相同的。以上是关于如何正确调用 Parallel.ForEach 循环中的调用异步方法[重复]的主要内容,如果未能解决你的问题,请参考以下文章
C# - 用于服务调用的 Parallel.Foreach()