2010-11-15 16 views
1

J'ai récemment profilé une application essayant de comprendre pourquoi certaines opérations étaient extrêmement lentes. L'une des classes de mon application est une collection basée sur LinkedList. Voici un aperçu de base, montrant seulement quelques méthodes et quelques peluches enlevés:Y a-t-il une collection LinkedList qui supporte les opérations de type dictionnaire?

public class LinkInfoCollection : PropertyNotificationObject, IEnumerable<LinkInfo> 
    { 

    private LinkedList<LinkInfo> _items; 

    public LinkInfoCollection() 
    { 
     _items = new LinkedList<LinkInfo>(); 
    } 

    public void Add(LinkInfo item) 
    { 
     _items.AddLast(item); 
    } 

    public LinkInfo this[Guid id] 
    { get { return _items.SingleOrDefault(i => i.Id == id); } } 

    } 

La collection est utilisée pour stocker des hyperliens (représenté par la classe LinkInfo) dans une seule liste. Cependant, chaque lien hypertexte a également une liste de liens hypertexte qui pointent vers lui, et une liste de liens hypertexte vers laquelle il pointe. Fondamentalement, c'est une carte de navigation d'un site Web. Comme cela signifie que vous pouvez avoir une récursion infinie lorsque les liens se renvoient les uns aux autres, j'ai implémenté ceci comme une liste chaînée - si je comprends bien, cela signifie pour chaque lien hypertexte, peu importe combien de fois il est référencé par un autre lien hypertexte. jamais une copie de l'objet.

La propriété ID dans l'exemple ci-dessus est un GUID. Avec cette longue description, mon problème est simple - selon le profileur, lors de la construction de cette carte pour un site Web relativement petit, l'indexeur mentionné ci-dessus est appelé au moins 27906 fois. Ce qui est un montant extraordinaire. Je dois encore m'entraîner s'il est vraiment nécessaire d'être appelé plusieurs fois, mais en même temps, j'aimerais savoir s'il y a une façon plus efficace de faire l'indexeur car c'est le goulot d'étranglement principal identifié par le profileur (aussi en supposant que ce n'est pas mentir!). J'avais toujours besoin du comportement de la liste chaînée car je ne veux certainement pas que plus d'une copie de ces hyperliens flotte autour de ma mémoire, mais je dois aussi pouvoir y accéder par une clé unique.

Quelqu'un a-t-il des conseils à donner pour améliorer les performances de cet indexeur? J'ai aussi un autre indexeur qui utilise un URI plutôt qu'un GUID, mais c'est moins problématique car la construction des liens entrants/sortants est faite par GUID.

Merci; Richard Moss

+3

_Pourquoi avez-vous besoin d'un comportement de liste liée? – SLaks

+0

Eh bien. Normalement, je n'ai pas de collections capables de récursion infinie. Mais si le lien A pointe vers le lien B qui pointe également vers le lien A, cela signifie que vous pouvez heureusement rebondir de a à b à a à b pour toujours et un jour. J'ai donc pensé à partir de la description d'une LinkedList qu'il serait mieux servi pour le travail. Peut-être que je me trompe, et un dictionnaire suffira ...mais je ne saurai pas à moins que je demande à quelqu'un avec plus de connaissances :) –

+0

Collections ne se soucie pas des références dans son contenu. LinkedList est vraiment le mauvais outil pour le travail. – SLaks

Répondre

5

Vous devez utiliser un Dictionary<Guid, LinkInfo>.

+1

Ou [KeyedCollection ] (http://msdn.microsoft.com/en-us/library/ms132438.aspx) – dtb

+0

Normalement je fais des collections de base de Dictionary, c'est la première fois que j'ai utilisé LinkedList comme base. Comme MSDN indique "Vous pouvez supprimer des noeuds et les réinsérer, soit dans la même liste ou dans une autre liste, ce qui entraîne aucun objet supplémentaire alloué sur le tas." L'utilisation d'un dictionnaire annulerait sûrement cet avantage? Ou ne vaut-il pas la peine de s'inquiéter? –

+0

@Richard: Le seul problème avec un dictionnaire est qu'il aura parfois besoin de redimensionner son tableau interne (en créant un nouveau et en supprimant l'ancien). ** Ne vous inquiétez pas à ce sujet **. Si vous êtes concerné, vous pouvez définir la capacité à l'avance pour éviter les redimensionnements inutiles. – SLaks

2

Vous n'avez pas besoin d'utiliser LinkedList pour avoir une seule copie de chaque LinkInfo en mémoire. Rappelez-vous que LinkInfo est un type de référence géré, et que vous pouvez donc le placer dans n'importe quelle collection, et ce sera juste une référence à l'objet placé dans la liste, pas une copie de l'objet lui-même. Cela dit, j'implémenterais la classe LinkInfo comme contenant deux listes de Guids: une pour les choses auxquelles elle est liée, une pour les objets qui y sont liés. J'aurais juste un Dictionary<Guid, LinkInfo> pour stocker tous les liens. Le dictionnaire est une recherche très rapide, je pense que cela aidera votre performance. Le fait que ce [] soit appelé 27 000 fois ne me semble pas être un gros problème, mais ce qui le fait apparaître dans votre profileur est probablement l'appel SingleOrDefault sur le LinkedList. Les listes liées sont les mieux adaptées aux situations nécessitant des insertions rapides, en particulier au milieu de la liste. Pour des recherches rapides, ce qui est probablement plus important ici, laissez le dictionnaire faire son travail avec les tables de hachage.