69 votes

Pourquoi LINQ .Where (prédicat) .First () est-il plus rapide que .First (prédicat)?

Je suis en train de faire des tests de performance et a constaté qu'une expression LINQ comme

result = list.First(f => f.Id == i).Property

est plus lent que

result = list.Where(f => f.Id == i).First().Property

Cela semble contre-intuitif. J'aurais pensé que la première expression serait plus rapide car il peut arrêter une itération sur la liste dès que le prédicat est satisfait, alors que j'aurais pensé que l' .Where() expression peut itérer sur l'ensemble de la liste avant d'appeler .First() sur le sous-ensemble. Même si celui-ci ne court-circuit, il ne devrait pas être plus rapide que d'utiliser directement pour la Première, mais il est.

Ci-dessous sont deux très simples tests unitaires qui illustrent cette situation. Lorsqu'il est compilé avec optimisation sur les TestWhereAndFirst est environ 30% plus rapide que TestFirstOnly .Net et Silverlight 4. J'ai essayé de faire le prédicat de retour plus de résultats, mais la différence de performance est la même.

Quelqu'un peut-il expliquer pourquoi .First(fn) plus lente que l' .Where(fn).First()? Je vois un semblable résultat contre-intuitif avec .Count(fn) par rapport à l' .Where(fn).Count().

private const int Range = 50000;

private class Simple
{
   public int Id { get; set; }
   public int Value { get; set; }
}

[TestMethod()]
public void TestFirstOnly()
{
   List<Simple> list = new List<Simple>(Range);
   for (int i = Range - 1; i >= 0; --i)
   {
      list.Add(new Simple { Id = i, Value = 10 });
   }

   int result = 0;
   for (int i = 0; i < Range; ++i)
   {
      result += list.First(f => f.Id == i).Value;
   }

   Assert.IsTrue(result > 0);
}

[TestMethod()]
public void TestWhereAndFirst()
{
   List<Simple> list = new List<Simple>(Range);
   for (int i = Range - 1; i >= 0; --i)
   {
      list.Add(new Simple { Id = i, Value = 10 });
   }

   int result = 0;
   for (int i = 0; i < Range; ++i)
   {
      result += list.Where(f => f.Id == i).First().Value;
   }

   Assert.IsTrue(result > 0);
}

50voto

arx Points 10667

J'ai eu les mêmes résultats: où + était plus rapide que le premier.

Comme Jon a noté, Linq utilise une évaluation paresseuse et la performance doit donc être (et est) globalement similaire pour les deux méthodes.

Looking in Reflector, First utilise une simple boucle foreach pour parcourir la collection, mais Where dispose de plusieurs itérateurs spécialisés pour différents types de collection (tableaux, listes, etc.). Vraisemblablement, c’est ce qui donne à Where le petit avantage.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X