Я работаю с коллекцией List < > , добавляя новые объекты в коллекцию внутри 2 вложенных циклов. В коллекцию добавлено 500000 элементов после завершения цикла.
Во-первых, операция присоединения работает хорошо, но вскоре после того, как можно заметить снижение производительности, для последних тысяч элементов время задержки невыносимо.
Я пробовал различные трюки (инициализация коллекции с определенным размером - 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 пустыми прогнозами.
По мере того, как совпадающий словарь обновляется одним из компьютерных потоков, он вызывает событие, которое вызывает упомянутый выше метод, который в свою очередь обновляет список (prediccionList).
Максимальное количество записей, которые могут быть сохранены в списке prediccionList (в данном случае), составляет около 500000 записей, но потеря производительности может быть замечена после добавления в список 40000 записей.
Код может показаться немного ржавым, поскольку я пробовал различные трюки оптимизации (замените foreach'es на for, вычислите счет за пределами циклов, замените объект List < LinkedList < > и т.д.). Наконец, я пришел к выводу, что часть, которая замедляет время выполнения, представляет собой строку "prediccionList.Add(p);".
Объекты, добавленные в список, являются экземплярами класса Prediccion; этот объект, который я считаю не очень крутым, содержит только 7 полей.
Использование памяти
Я присоединяю результат к профилированию памяти. Используемая память не превосходит 256 МБ, поэтому я не верю, что здесь проблема должна быть проблемой.