没有内存泄漏或错误,但我的代码呈指数级减慢 C#



我对这个问题感到困惑。我相信我只是错过了一个简单的问题,但我正处于需要第二意见来指出我错过的任何明显问题的地步。我最小化了我的代码并简化了它,所以它只显示了它的一小部分。完整的代码只是在我下面添加的许多不同的计算。

for (int h = 2; h < 200; h++)
{
var List1 = CalculateSomething(testValues, h);
var masterLists = await AddToRsquaredList("Calculation1", h, actualValuesList, List1, masterLists.Item1, masterLists.Item2);
var List2 = CalculateSomething(testValues, h);
masterLists = await AddToRsquaredList("Calculation2", h, actualValuesList, List2, masterLists.Item1, masterLists.Item2);
var List3 = CalculateSomething(testValues, h);
masterLists = await AddToRsquaredList("Calculation3", h, actualValues, List3, masterLists.Item1, masterLists.Item2);
}
public static async Task<(List<RSquaredValues3>, List<ValueClass>)> AddToRsquaredList(string valueName, int days, 
IEnumerable<double> estimatedValuesList, IEnumerable<double> actualValuesList, 
List<RSquaredValues3> rSquaredList, List<ValueClass> valueClassList)
{
try
{
RSquaredValues3 rSquaredValue = new RSquaredValues3
{
ValueName = valueName,
Days = days,
RSquared = GoodnessOfFit.CoefficientOfDetermination(estimatedValuesList, actualValuesList),
StdError = GoodnessOfFit.PopulationStandardError(estimatedValuesList, actualValuesList)
};
int comboSize = 15;
double max = 0;
var query = await rSquaredList.OrderBy(i => i.StdError - i.RSquared).DistinctBy(i => i.ValueName).Take(comboSize).ToListAsync().ConfigureAwait(false);
if (query.Count > 0)
{
max = query.Last().StdError - query.Last().RSquared;
}
else
{
max = 10000000;
}
if ((rSquaredValue.StdError - rSquaredValue.RSquared < max || query.Count < comboSize) && rSquaredList.Contains(rSquaredValue) == false)
{
rSquaredList.Add(rSquaredValue);
valueClassList.Add(new ValueClass { ValueName = rSquaredValue.ValueName, ValueList = estimatedValuesList, Days = days });
}
}
catch (Exception ex)
{
ThrowExceptionInfo(ex);
}
return (rSquaredList, valueClassList);
}

显然StdError - RSquared有意义,因此更改RSquaredValues3以公开该值(即在构造时计算一次,因为值不会更改),而不是在处理循环期间在多个位置重新计算它。

此新属性中的值是列表排序的方式。与其一遍又一遍地对列表进行排序,不如首先考虑按该顺序保留列表中的项目。为此,您可以确保每次添加项目时,都会将其插入列表中的正确位置。这称为插入排序。(我认为由于重复的"键",SortedList<TKey,TValue>是不合适的。

可以进行类似的改进以避免对DistinctBy(i => i.ValueName)的需求。如果您只对不同的值名称感兴趣,请考虑避免插入该项目(如果它没有提供改进)。

您的List在处理过程中需要增长 - 在引擎盖下,列表每次增长都会翻倍,因此增长次数为 O(log(n))。您可以在施工中指定建议的容量。如果在开始时指定足够大的预期大小,则列表在处理过程中不需要执行此操作。

据我所知,ToListAsyncawait并没有为这段代码增加任何优势。

rSquaredList.Contains(rSquaredValue) == false的检查看起来像是冗余检查,因为这是无法插入到列表中的新实例化项的引用比较。因此,您可以删除它以使其运行得更快。

使用所有这些Taskawait,您目前实际上并没有获得任何东西,因为您有一个线程处理它并按顺序等待执行,因此它似乎都是开销。我不确定您是否可以并行化此工作负载,但从 2 到 200 的主循环似乎是Parallel.For()循环的主要候选者。如果实现并行性以避免死锁问题,则还应考虑对主列表使用System.Collections.Concurrent.ConcurrentBag()

最新更新