2009-08-04 6 views
4

Que se passe-t-il exactement dans les coulisses d'une requête LINQ par rapport à une collection d'objets? Est-ce du sucre syntaxique ou est-ce qu'il se passe quelque chose d'autre qui en fait une question plus efficace?Performances LINQ

Répondre

2

C'est juste du sucre syntaxique - il n'y a pas de magie impliquée.

Vous pouvez écrire le code équivalent en "longhand", en C# ou autre, et il aurait la même performance. (Le compilateur va bien sûr produire du code efficace, donc le code qu'il produit peut être une fraction plus efficace que le code que vous écrivez vous-même, simplement parce que vous ne connaissez pas le moyen le plus performant de écrivez ce code.)

12

Voulez-vous dire en termes d'expression d'une requête, ou que fait la requête dans les coulisses?

Les expressions de requête sont d'abord développées en C# "normal". Par exemple:

var query = from x in source 
      where x.Name == "Fred" 
      select x.Age; 

se traduit à:

var query = source.Where(x => x.Name == "Fred") 
        .Select(x => x.Age); 

La exacte signifie cela dépend du type de source bien sûr ... en LINQ aux objets, il implémente généralement IEnumerable<T> et Enumerable les méthodes d'extension entrent en jeu ... mais il pourrait s'agir d'un ensemble différent de méthodes d'extension. (LINQ to SQL utiliserait les méthodes d'extension Queryable, par exemple.)

Maintenant, supposons que nous sont LINQ aux objets ... après l'expansion de la méthode d'extension, le code ci-dessus devient:

var query = Enumerable.Select(Enumerable.Where(source, x => x.Name == "Fred"), 
           x => x.Age); 

Ensuite, les implémentations de Select et Where deviennent importantes. Laissant de côté la vérification des erreurs, ils sont quelque chose comme ceci:

public static IEnumerable<T> Where<T>(this IEnumerable<T> source, 
             Func<T, bool> predicate) 
{ 
    foreach (T element in source) 
    { 
     if (predicate(element)) 
     { 
      yield return element; 
     } 
    } 
} 

public static IEnumerable<TResult> Select<TSource, TResult> 
    (this IEnumerable<TSource> source, 
    Func<TSource, TResult> selector) 
{ 
    foreach (TSource element in source) 
    { 
     yield return selector(element); 
    } 
} 

Ensuite il y a l'expansion des blocs itérateur dans des machines d'état, que je pas ici mais que j'ai un article about. Enfin, il y a la conversion des expressions lambda en méthodes supplémentaires + création d'instance de délégué appropriée (ou arbres d'expression, selon les signatures des méthodes appelées).

Donc, fondamentalement, LINQ utilise un beaucoup de fonctionnalités intelligentes de C#:

  • conversions d'expression Lambda (dans les instances de délégués et d'arbres d'expression)
  • Méthodes d'extension
  • d'inférence de type pour les méthodes génériques
  • Blocs d'itération
  • Types souvent anonymes (à utiliser dans les projections)
  • Souvent frappe implicite pour les variables locales
  • expression de requête traduction

Cependant, les opérations individuelles sont assez simples - ils ne réalisent pas l'indexation, etc. Les joints et les regroupements sont effectués en utilisant des tables de hachage, mais les requêtes simples comme "où" sont juste linéaires. N'oubliez pas que LINQ to Objects traite généralement les données comme une séquence lisible uniquement en avant - il ne peut pas faire des choses comme une recherche binaire. Normalement, je m'attendrais à ce que les requêtes manuscrites soient légèrement plus rapides que LINQ to Objects car il y a moins de couches d'abstraction, mais elles seront moins lisibles et la différence de performance ne sera généralement pas significative.

Comme toujours pour les questions de performance: en cas de doute, mesurez!

+0

Je voulais dire ce qu'il fait dans les coulisses. Par exemple, j'ai une collection d'objets. Je peux écrire une boucle For qui itère à travers la collection entière et vérifie juste la propriété pour la valeur dont j'ai besoin dans chaque objet ou je peux utiliser LINQ. LINQ semble être plus rapide dans de nombreux cas selon ce que j'ai lu. Ma question est pourquoi est-ce plus rapide et comment fait-il les recherches? – Crios

+0

LINQ ne sera généralement pas plus rapide que le code équivalent - bien que je pense qu'il existe d'autres projets pour fournir des recherches indexées, par exemple. Si vous pouviez donner un exemple concret où vous vous attendez à ce que LINQ soit plus rapide, ce serait utile. –

3

Si vous avez besoin de meilleures performances, essayez i4o - Index for Objects. Il construit des objets en mémoire pour les grandes collections (pensez à plus de 100 000 lignes), que LINQ utilise ensuite pour accélérer les requêtes. Vous avez besoin de beaucoup de données pour faire ce travail, mais les améliorations sont impressionnantes.

http://www.codeplex.com/i4o