2012-12-03 3 views
2

Contexte: mon jeu utilise un système de composants. J'ai une classe Entity qui a une liste de IComponent instances dans un List<IComponent>. Ma mise en œuvre actuelle de Entity.GetComponent<T>() est:Linq Slowness sur un seul appel

return (T)this.components.Single(c => c is T);

Après avoir ajouté la détection de collision, j'ai remarqué mon jeu est tombé à 1FPS. Le profilage a révélé que le coupable était ce même appel (appelé 3000 fois par image). 3000x côté, j'ai remarqué que l'appel 300k fois cela prend environ 2 secondes. J'optimisé à simple boucle itérative:

foreach (IComponent c in this.components) { 
    if (c is T) { 
    return (T)c; 
    } 
} 

return default(T); 

Ce code fonctionne maintenant dans environ 0,4s, ce qui est un ordre de grandeur mieux. Je pensais Single serait beaucoup plus efficace qu'une seule boucle foreach. Que se passe t-il ici?

+1

Vous pouvez remplacer Single par FirstOrDefault qui retournera simplement la première occurrence, devrait être aussi rapide que votre boucle itérative – Martheen

+1

Si vous préférez faire abstraction de la conversion, vous pouvez utiliser 'OfType ()' comme ceci: 'return this .components.OfType () .FirstOrDefault(); ' –

+0

Merci Martheen et @RiskyMartin, je vais incorporer vos suggestions. – ashes999

Répondre

6

Le doc pour Single dit:

Renvoie le seul élément d'une séquence, et jette une exception si il n'y a pas un seul élément de la séquence.

D'autre part First:

Le premier élément de la séquence qui passe le test de la fonction de prédicat spécifiée .

Ainsi, avec Single vous traversez toute la séquence sans short circuiting, qui est ce que la boucle foreach fait ci-dessus. Donc, utilisez First ou FirstOrDefault au lieu de Single.

+0

Sémantiquement, 'Single' renvoie une exception si plus d'un objet répondant à ce critère existe. Comment puis-je garder ce comportement si j'utilise 'First' – ashes999

+0

Vous ne pouvez pas faire cela sans parcourir toute la liste. Si vous avez besoin de connaître les dupes, vous devez utiliser Single ou gérer votre propre structure de données qui répertorie le nombre de chaque type existant dans la mémoire. – Candide

+0

Merci, j'apprécie votre aide pour comprendre cela. – ashes999

1

Unique parcourt toute la collection et s'assure qu'un seul élément est trouvé. Donc, votre meilleure performance est toujours O (N)

Votre recherche itérative est également soumise à des performances O (N), mais c'est le pire des cas.

Source: List<T>.Single Method

+0

Notez que je ne suis pas exactement sûr que .Single est une recherche itérative, il pourrait également passer par la collection plusieurs fois. – Mataniko

Questions connexes