J'ai fait une fonction pour trouver récursivement le premier élément ou par défaut qui correspond à une condition (premier bloc de code). Resharper m'a suggéré de changer quelques lignes dans une seule ligne LINQ (deuxième bloc de code).D'où vient cette performance LINQ?
Je me demandais si la suggestion Resharper me donnerait la même performance et la même empreinte mémoire. J'ai fait un test pour la performance (3ème bloc de code). Le résultat est exactement ce à quoi je m'attendais. Pourquoi la différence est si grande?
8156 milliseconds
Laure
23567 milliseconds
Laure LINQ
D'où vient cette différence ??? Pourquoi les résultats ne sont-ils pas les mêmes? ... ou du moins, plus proches?
public static T RecursiveFirstOrDefault<T>(this T item, Func<T, IEnumerable<T>> childrenSelector, Predicate<T> condition)
where T : class // Hierarchy implies class. Don't need to play with "default()" here.
{
if (item == null)
{
return null;
}
if (condition(item))
{
return item;
}
foreach (T child in childrenSelector(item))
{
T result = child.RecursiveFirstOrDefault(childrenSelector, condition);
if (result != null)
{
return result;
}
}
return null;
}
Mais ReSharper m'a suggéré de convertir le bloc foreach à une requête LINQ comme suit:
public static T RecursiveFirstOrDefaultLinq<T>(this T item, Func<T, IEnumerable<T>> childrenSelector, Predicate<T> condition)
where T : class // Hierarchy implies class. Don't need to play with "default()" here.
{
if (item == null)
{
return null;
}
if (condition(item))
{
return item;
}
// Resharper change:
return childrenSelector(item).Select(child => child.RecursiveFirstOrDefaultLinq(childrenSelector, condition)).FirstOrDefault(result => result != null);
}
Test:
private void ButtonTest_OnClick(object sender, RoutedEventArgs e)
{
VariationSet varSetResult;
Stopwatch watch = new Stopwatch();
varSetResult = null;
watch.Start();
for(int n = 0; n < 10000000; n++)
{
varSetResult = Model.VariationRef.VariationSet.RecursiveFirstOrDefault((varSet) => varSet.VariationSets,
(varSet) => varSet.Name.Contains("Laure"));
}
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds.ToString() + " milliseconds");
Console.WriteLine(varSetResult.Name);
watch.Reset();
varSetResult = null;
watch.Start();
for(int n = 0; n < 10000000; n++)
{
varSetResult = Model.VariationRef.VariationSet.RecursiveFirstOrDefaultLinq((varSet) => varSet.VariationSets,
(varSet) => varSet.Name.Contains("Laure"));
}
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds.ToString() + " milliseconds");
Console.WriteLine(varSetResult.Name + " LINQ");
}
Je dois aller aujourd'hui ... L'espoir de répondre correctement sur les tests: x86, sortie sur une machine 12 de base, windows 7, 4.5 Framework.Net,
Ma conclusion:
Dans mon cas, il est ~ 3x plus rapide dans la version non linq. La lisibilité est meilleure dans LINQ mais qui se soucient QUAND c'est dans une bibliothèque où vous devriez seulement vous rappeler ce qu'il fait et comment l'appeler (dans ce cas - pas un cas absolu général). LINQ est presque toujours plus lent qu'une bonne méthode codée. Je PERSONNELLEMENT saveur:
- LINQ: Lorsque le rendement est pas vraiment un problème (la plupart des cas) dans code de projet spécifique
- non Linq: Lorsque la performance est un problème dans le code de projet spécifique, et lorsqu'il est utilisé Une bibliothèque et où le code devrait être stable et fixe où l'utilisation de la méthode devrait être bien documentée et nous ne devrait pas vraiment besoin de creuser à l'intérieur.
Le compilateur sous-jacent compile le code LINQ radicalement différent de code foreach, c'est là votre différence vient. –
Vous ne devez pas réinitialiser la minuterie pour obtenir le nombre correct pour la deuxième itération de test? – entropic
@entropic, merci ... :-(!!!!! –