Я работаю с коллекцией List <>, добавляю новые объекты в коллекцию внутри 2 вложенных циклов. После завершения циклов в коллекцию добавлено около 500 000 элементов.
Сначала операция добавления работает хорошо, но вскоре после того, как можно заметить снижение производительности, для последних тысяч элементов время задержки становится невыносимым.
Я испробовал различные приемы (инициализация коллекции с определенным размером - 500000), заменив List <> на коллекцию LinkedList <>, но это не сильно помогло.
Можете ли вы порекомендовать мне совет для решения проблемы? Мне интересно изменить структуру на более оптимизированную - LinkedList <>, например, работает лучше, чем List <> с такими операциями, как сложение.
Метод, который обновляет список
private void UpdateForecastList(ConcurrentDictionary<Int32, RegistroSalidaProductoPrevision> prediccion, bool soloMejoresMetodos = true)
{
foreach (KeyValuePair<int, RegistroSalidaProductoPrevision> kvp in prediccion)
{
KeyValuePair<int, RegistroSalidaProductoPrevision> localKvp = kvp;
IList<Prediccion> pExistente = prediccionList.Where(p => p.Id == localKvp.Key).ToList();
Articulo articulo = (articuloList.Where(a => a.Id == localKvp.Key)).First();
if (pExistente.Count > 0)
{
foreach (var p in pExistente)
{
prediccionList.Remove(p);
}
}
if (kvp.Value.Previsiones.Count > 0)
{
var previsiones = kvp.Value.Previsiones.Where(prevision => prevision.Value.LPrevision[1] != null).ToList();
int previsionesCount = previsiones.Count;
for (int a = 0; a < previsionesCount; a++)
{
var registros = previsiones[a].Value.LPrevision[1].Serie;
int c = registros.Count;
if (soloMejoresMetodos)
{
if (localKvp.Value.MejorMetodo != previsiones[a].Key) continue;
for (int i = 0; i < c; i++)
{
var p = new Prediccion()
{
Id = articulo.Id,
Nombre = articulo.Codigo,
Descripcion = articulo.Descripcion,
NombreMetodo =
Utils.SplitStringByCapitals(previsiones[a].Value.NombreMetodo),
Fecha = registros[i].Fecha,
PrediccionArticulo = Math.Round(registros[i].Cantidad, 2),
EsMejorMetodo =
(previsiones[a].Value.NombreMetodo == localKvp.Value.MejorMetodo)
? true
: false
};
// This line experiences performance loss
prediccionList.Add(p);
}
}
else
{
for (int i = 0; i < c; i++)
{
prediccionList.Add(new Prediccion()
{
Id = articulo.Id,
Nombre = articulo.Codigo,
Descripcion = articulo.Descripcion,
NombreMetodo = previsiones[a].Value.NombreMetodo,
Fecha = registros[i].Fecha,
PrediccionArticulo =
Math.Round(registros[i].Cantidad, 2),
EsMejorMetodo =
(previsiones[a].Value.NombreMetodo ==
localKvp.Value.MejorMetodo)
? true
: false
});
}
}
}
}
else
{
prediccionList.Add(new Prediccion()
{
Id = articulo.Id,
Nombre = articulo.Codigo,
Descripcion = articulo.Descripcion,
NombreMetodo = kvp.Value.ErroresDatos[0].Texto,
});
}
}
}
Небольшое описание метода:
- метод считывает объект (параллельный словарь) и обновляет список (в данном случае LinkedList) с прогнозами, соответствующими определенной статье.
Параллельный объект словаря постоянно обновляется из различных потоков, которые одновременно обращаются к нему.
Список инициализируется нулевыми предсказаниями, соответствующими всем статьям; так, например, если у вас есть 700 статей, в начале список будет заполнен 700 пустыми прогнозами.
Когда параллельный словарь обновляется одним из вычислительных потоков, он вызывает событие, вызывающее упомянутый выше метод, который, в свою очередь, обновляет список (gneccionList).
Максимальное количество записей, которое может быть сохранено в предикате списков (в данном случае), составляет около 500000 записей, но снижение производительности можно заметить после добавления примерно 40000 записей в список.
Код может показаться немного ржавым, так как я пробовал различные приемы оптимизации (заменим foreach'ы на for, вычислим число вне циклов, заменим объект List <> на LinkedList <> и т. Д.). Наконец, я пришел к выводу, что часть, которая замедляет время выполнения, - это строка "ForeccionList.Add (p);".
Объекты, которые добавляются в список, являются экземплярами класса Prediccion; этот объект я считаю не очень тяжелым, он содержит только 7 полей.
Использование памяти
Я прикрепляю результат из профилирования памяти. Используемая память не превышает 256 МБ, поэтому я не считаю, что память должна быть проблемой здесь.