[英]Parallelizing a task using .AsParallel().ForAll or Parallel.ForEach performance issue
[英]Using AsParallel() and/or Parallel.ForEach on a virtual machine
我们的Web应用程序托管在具有8个vCPU的虚拟机上。 我们有一个密集的数据操作,该操作按夜间计划运行(控制台应用程序/ Windows任务计划程序),我想以某种方式对其进行并行化。 该操作对许多数据集进行多次迭代以计算不同的统计信息。 当前,任务管理器在运行时显示其CPU使用率从未超过13%。
这是被调用的方法之一的代码(Web应用程序是一个大型问卷):
Dictionary<string, List<decimal>> decimalStats = new Dictionary<string, List<decimal>>();
using (var db = new PDBContext())
{
IEnumerable<FinancialYear> financialYears = db.FinancialYears;
IEnumerable<Section> sections;
IEnumerable<Question> questions;
IQueryable<int> orgIds = db.Organisations.Where(l => l.Sector.IndustryID == 1).Select(m => m.OrganisationID);
IQueryable<int> subSectionIds;
foreach (var financialYear in financialYears)
{
sections = db.Sections.Where(l => orgIds.Contains(l.OrganisationID) && l.FinancialYearID == financialYear.FinancialYearID && l.IsVerified.Value);
foreach (var section in sections)
{
subSectionIds = db.SubSections.Where(l => l.SectionID == section.SectionID).Select(m => m.SubSectionID);
questions = db.Questions.Where(l => subSectionIds.Contains(l.SubSectionID.Value));
foreach (var question in questions)
{
var answer = db.Answers.Where(l => l.QuestionID == question.QuestionID && l.OrganisationID == section.OrganisationID && l.FinancialYearID == financialYear.FinancialYearID).FirstOrDefault();
if (answer != null)
{
string key = question.QuestionID + "#" + financialYear.FinancialYearID;
decimal val;
if (decimal.TryParse(answer.Text, out val))
{
if (decimalStats.ContainsKey(key))
{
((List<decimal>)decimalStats[key]).Add(val);
}
else
{
List<decimal> vals = new List<decimal>();
vals.Add(val);
decimalStats.Add(key, vals);
}
}
}
}
}
}
foreach (KeyValuePair<string, List<decimal>> entry in decimalStats)
{
List<decimal> vals = ((List<decimal>)entry.Value).OrderBy(l => l).ToList();
if (vals.Count > 0)
{
// lots of stuff to calculate various statistics about the data
}
}
}
我已经将上面的代码简化了很多。 我希望它隔离了我可以使用一些并行执行的区域。
我尝试过使用以下方法的不同组合:
IEnumerable<FinancialYear> financialYears = db.FinancialYears.AsParallel();
Parallel.ForEach(financialYears, financialYear => { });
sections = db.Sections.Where(l => orgIds.Contains(l.OrganisationID) && l.FinancialYearID == financialYear.FinancialYearID && l.IsVerified.Value).AsParallel();
...但是我没有做任何事情将CPU使用率提高到13%以上,执行该方法所需的时间几乎保持不变。 我在这里想念什么技巧? 并行编程对我来说是新手,所以我试图尽可能简单地使用PLINQ / TPL。
问题最可能是数据库查询而不是CPU。
我建议不要着重于使CPU操作并行化,而应着重于最大程度地减少查询数量和使来自这些查询的数据数量最大化。
例如以下行:
var answer = db.Answers.Where(l => l.QuestionID == question.QuestionID && l.OrganisationID == section.OrganisationID && l.FinancialYearID == financialYear.FinancialYearID).FirstOrDefault();
可能是性能问题,因为它每年,每个部分和每个问题都涉及数据库,这很多。 您应该更喜欢通过单个查询将所有内容预加载到内存中并使用内存中的数据。
另外,我忘了提:在尝试任何一种性能优化之前,您都应该对代码进行概要分析 。 这样,您就知道问题是受I / O约束还是算法问题,这将决定您应该优化代码的方式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.