Estoy trabajando con una lista <> colección, agregando nuevos objetos a la colección dentro de 2 bucles anidados. Hay unos 500000 elementos agregados a la colección, una vez que los bucles terminan de ejecutarse.C# List <> Add() método rendimiento
Al principio, la operación de adición funciona bien, pero poco después puede notarse una disminución en el rendimiento, para los últimos miles de elementos, el tiempo de retardo es insoportable.
He intentado varios trucos (inicializando la colección con un cierto tamaño - 500000), reemplazando la lista <> con una colección LinkedList <>, pero no ayudó demasiado.
¿Me puede recomendar un consejo para solucionar el problema? Me resulta interesante cambiar la estructura por una más optimizada: LinkedList <> por ejemplo funciona mejor que List <> con operaciones como add.
método que actualiza la lista
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,
});
}
}
}
pequeña descripción del método: - el método lee un objeto (un diccionario concurrente) y actualiza una lista (en este caso un LinkedList) con el pronósticos correspondientes a un determinado artículo.
El objeto de diccionario simultáneo se actualiza constantemente desde varios subprocesos que acceden a él simultáneamente.
La lista se inicializa con predicciones nulas correspondientes a todos los artículos; así, por ejemplo, si tiene 700 artículos, al principio la lista se completará con 700 pronósticos en blanco.
Como el diccionario concurent se actualiza mediante uno de los hilos informáticos, se genera un evento que llama al método mencionado anteriormente, que a su vez actualiza la lista (prediccionList).
El número máximo de registros que podrían mantenerse en la prediccionList (en este caso) es de aproximadamente 500000 registros, pero la pérdida en el rendimiento podría notarse después de agregar unos 40000 registros en la lista.
El código puede parecer un poco oxidado, como he intentado varios trucos optimizaciones (sustituyen a los foreach'es por de, calculan el recuento de fuera de los bucles, sustituir la lista <> objeto con una LinkedList <> etc.). Finalmente llegué a la conclusión de que la parte que ralentiza el tiempo de ejecución es la línea "prediccionList.Add (p);".
Los objetos que se agregan a la lista son instancias de la clase Prediccion; este objeto no lo considero muy pesado, solo contiene 7 campos.
Uso de memoria
adjunto el resultado de una perfiles de memoria. La memoria utilizada no supera los 256 MB, por lo que no creo que la memoria sea un problema aquí.
¿De dónde saca los 500000 artículos? –
¿Podría proporcionar una muestra de código que reproduzca el problema? – alun
¿Qué tipo de objetos se están agregando? – jalf