Est-il un impact sur les performances lors de l'appel de ToList()?
Lors de l'utilisation de ToList()
, est-il un impact sur la performance qui doit être pris en compte?
J'ai écrit une requête pour extraire les fichiers d'un répertoire, qui est la requête:
string[] imageArray = Directory.GetFiles(directory);
Cependant, depuis que je aime travailler avec List<>
au lieu de cela, j'ai décidé de mettre en...
List<string> imageList = Directory.GetFiles(directory).ToList();
Donc, est-il une sorte d'impact sur les performances qui devraient être considérés au moment de décider de faire une conversion comme celle - ci, ou seulement à considérer lorsque vous traitez avec un grand nombre de fichiers? Est-ce un négligeable de conversion?
- +1 intéressée de connaître la réponse aussi. À mon humble avis, à moins que l'application est critique pour les performances, je pense que j'ai toujours utiliser un
List<T>
en faveur d'uneT[]
si elle rend le code plus logique/lisible et maintenable (sauf bien sûr si la conversion était causant ainsi des problèmes de performances dans ce cas, je l'avais re-visite, je suppose). - Création d'une liste à partir d'un tableau doit être super bon.
- Je ne spécifiez le type de données aussi précises que j'ai besoin de faire un travail. Si je n'ai pas à appeler
Add
ouRemove
, je laisserais commeIEnumerable<T>
(ou encore mieuxvar
) - Je pense que, dans ce cas, il est préférable d'appeler
EnumerateFiles
au lieu deGetFiles
, donc un seul tableau sera créé. - Si vous avez beaucoup de fichiers dans le répertoire de voir cette réponse stackoverflow.com/questions/7865159/...
GetFiles(directory)
, comme il est mis en œuvre .NET actuellement, à peu près n'new List<string>(EnumerateFiles(directory)).ToArray()
. DoncGetFiles(directory).ToList()
crée une liste, crée un tableau à partir de ce, crée ensuite une liste de nouveau. Comme 2kay dit, vous devriez être en préférantEnumerateFiles(directory).ToList()
ici.
InformationsquelleAutor Cody | 2013-03-20
Vous devez vous connecter pour publier un commentaire.
IEnumerable.ToList()
Oui,
IEnumerable<T>.ToList()
n'ont un impact sur les performances, c'est un O(n) opération si elle va probablement nécessiter une attention particulière à la performance des opérations critiques.La
ToList()
opération va utiliser leListe(IEnumerable<T> collection)
constructeur. Ce constructeur doit faire une copie du tableau (plus généralementIEnumerable<T>
), sinon les modifications futures de l'origine de la matrice de changement de la sourceT[]
aussi qui ne serait pas souhaitable en général.Je voudrais réitérer cela ne faire une différence avec une liste énorme, la copie des morceaux de mémoire est bien une opération rapide à effectuer.
Conseil pratique,
As
vsTo
Vous remarquerez dans LINQ, il existe plusieurs méthodes qui commencent par
As
(commeAsEnumerable()
) etTo
(commeToList()
). Les méthodes qui commencent parTo
nécessitent une conversion comme ci-dessus (ie. peut influer sur les performances), et les méthodes qui commencent parAs
ne vous demanderons juste besoin de quelques fonte ou simple opération.Plus de détails sur
List<T>
Ici est un peu plus de détails sur la façon
List<T>
œuvres dans le cas où vous êtes intéressé 🙂Un
List<T>
utilise également une construction appelée un tableau dynamique qui doit être redimensionnée sur demande, cet événement de redimensionnement de copier le contenu d'un vieux tableau à la nouvelle tableau. Donc, il commence petit et augmente la taille si nécessaire.C'est la différence entre le
Capacité
etCount
attributs surList<T>
.Capacity
se réfère à la taille de la matrice de derrière les coulisses,Count
est le nombre d'éléments dans laList<T>
qui est toujours<= Capacity
. Alors, lorsqu'un élément est ajouté à la liste, il augmente dernièresCapacity
, la taille de laList<T>
est doublé et le tableau est copié.List(IEnumerable<T> collection)
constructeur vérifie si la collecte paramètre estICollection<T>
, puis crée un nouveau tableau interne avec la taille nécessaire tout de suite. Si le paramètre n'est pasICollection<T>
, constructeur parcourt et des appelsAdd
pour chaque élément.Oui, bien sûr. En théorie, le
i++
a un impact sur les performances, il ralentit le programme pour peut-être un peu de tiques.Ce n'
.ToList
faire?Lorsque vous appelez
.ToList
, le code appelleEnumerable.ToList()
qui est une méthode d'extension quireturn new List<TSource>(source)
. Dans le constructeur, dans les pires circonstances, elle passe à travers l'élément de conteneur et de les ajouter un par un dans un nouveau conteneur. De sorte que son comportement affecte peu sur les performances. Il est impossible d'être une performance bouteille de cou de votre application.Ce qui ne va pas avec le code dans la question
Directory.GetFiles
passe par le dossier et renvoie tous les noms de fichiers immédiatement dans la mémoire, il a un potentiel de risque que le string[] les coûts de beaucoup de mémoire, ce qui ralentit tout.Ce qui doit être fait ensuite
Il dépend. Si vous(ainsi que votre logique métier) garantit que le montant fichier dans le dossier est toujours petit, le code est acceptable. Mais il est toujours conseillé d'utiliser un paresseux version:
Directory.EnumerateFiles
en C#4. Cela ressemble plus à une requête, qui ne sera pas exécuté immédiatement, vous pouvez ajouter plus de requêtes sur elle comme:qui va s'arrêter recherche le chemin dès qu'un fichier dont le nom contient "monfichier" est trouvé. C'est évidemment a une meilleure performance alors
.GetFiles
.Oui, il est. À l'aide de la méthode d'extension
Enumerable.ToList()
va construire une nouvelleList<T>
objet de laIEnumerable<T>
source de la collection qui a bien sûr un impact sur les performances.Cependant, la compréhension de
List<T>
peut vous aider à déterminer si l'impact sur les performances est importante.List<T>
utilise un tableau (T[]
) pour stocker les éléments de la liste. Les tableaux ne peuvent pas être prolongé une fois qu'elles sont réparties de façonList<T>
va utiliser un tableau de taille pour stocker les éléments de la liste. Lorsque leList<T>
pousse au-delà de la taille de la sous-jacentes tableau un tableau doit être alloué et le contenu de l'ancien tableau doit être copié à la nouvelle largeur de la matrice avant de la liste peut se développer.Lorsqu'un nouveau
List<T>
est construit à partir d'unIEnumerable<T>
il y a deux cas:La source de la collection met en œuvre
ICollection<T>
: AlorsICollection<T>.Count
est utilisée pour obtenir la taille exacte de la source, de collecte et un correspondant de la sauvegarde de tableau est alloué avant tous les éléments de la collection source est copié dans le support de tableau à l'aide deICollection<T>.CopyTo()
. Cette opération est assez efficace et le seront probablement de la carte de l'UC instructions pour copier des blocs de mémoire. Cependant, en termes de performances de la mémoire est nécessaire pour le nouveau tableau et de cycles de PROCESSEUR requis pour la copie de tous les éléments.Sinon la taille de la collection source est inconnue et l'énumérateur de
IEnumerable<T>
est utilisé pour ajouter chaque élément source, un à la fois à la nouvelleList<T>
. Initialement, la sauvegarde de tableau est vide, et un tableau de taille 4 est créé. Alors quand ce tableau est trop petit, la taille est doublé, de sorte que le support de tableau se développe comme ce 4, 8, 16, 32, etc. Chaque fois que la sauvegarde de la matrice de pousse il doit être réalloués et tous les éléments stockés jusqu'à présent doivent être copiés. Cette opération est beaucoup plus coûteux par rapport à la première affaire où un tableau de la bonne taille peut être créé immédiatement.Aussi, si votre source de collecte contient dites 33 éléments de la liste sera à la fin à l'aide d'un tableau de 64 éléments de gaspiller de la mémoire.
Dans votre cas, la source de la collection est un tableau qui met en œuvre
ICollection<T>
donc l'impact sur les performances n'est pas quelque chose que vous devriez être préoccupé, à moins que votre source de tableau est très grand. L'appel deToList()
va simplement copier le tableau source et l'envelopper dans unList<T>
objet. Même la performance du deuxième cas n'est pas quelque chose à craindre pour les petites collections.De la question avec votre scénario précis, c'est que d'abord et avant tout votre véritable préoccupation à propos des performances du disque dur de la vitesse et l'efficacité du cache du lecteur.
De ce point de vue, l'impact est certainement négligeable, au point que PAS il n'a pas besoin d'être considéré.
MAIS SEULEMENT si vous avez vraiment besoin des caractéristiques de la
List<>
structure, éventuellement, soit vous rendre plus productif, ou votre algorithme plus convivial, ou quelque autre avantage. Sinon, vous êtes juste à dessein l'ajout d'un insignifiant de performances, pour aucune raison du tout. Dans ce cas, naturellement, vous ne devriez pas le faire! 🙂ToList()
crée une nouvelle Liste et mettez-les éléments, ce qui signifie qu'il ya un coût associé avec faireToList()
. Dans le cas de la petite collection, il ne sera pas très sensible des coûts, mais avoir une énorme collection peut causer une dégradation des performances dans le cas de l'utilisation ToList.En général, vous ne devriez pas utiliser ToList() à moins que le travail que vous faites ne peut pas se faire sans conversion de la collecte à la Liste. Par exemple, si vous voulez juste pour parcourir la collection, vous n'avez pas besoin d'effectuer ToList
Si vous êtes l'exécution de requêtes sur une source de données, par exemple une Base de données en utilisant LINQ to SQL, puis le coût de faire des ToList est beaucoup plus, parce que lorsque vous utilisez ToList avec LINQ to SQL au lieu de faire Retardé l'Exécution de charger les éléments en cas de besoin (ce qui peut être bénéfique dans de nombreux scénarios) instantanément charge des éléments à partir de la Base de données dans la mémoire
Elle le sera aussi (in)efficace de le faire:
Si vous démontez le code source du constructeur qui prend un
IEnumerable<T>
, vous allez voir, il va faire quelques choses:Appel
collection.Count
, donc sicollection
est unIEnumerable<T>
, il va forcer l'exécution. Sicollection
est un tableau, liste, etc. il devrait êtreO(1)
.Si
collection
implémenteICollection<T>
, il va enregistrer les éléments dans un tableau interne à l'aide de laICollection<T>.CopyTo
méthode. Il devrait êtreO(n)
, étantn
la longueur de la collection.Si
collection
ne pas mettre en œuvreICollection<T>
, il va itérer sur les éléments de la collection, et de les ajouter à une liste interne.Donc, oui, il va consommer plus de mémoire, car il doit créer une nouvelle liste, et dans le pire des cas, il sera
O(n)
, car il va parcourir lecollection
pour faire une copie de chaque élément.0(n)
oùn
est la somme des octets les chaînes de la collection originale occuper, pas le nombre des éléments (bon, pour être plus exacte n = octets/taille de mot)bool
,int
, etc.)? Vous n'avez donc pas à faire une copie de chaque chaîne dans la collection. Vous venez d'ajouter à la liste nouvelle.ToList Va créer une nouvelle liste et une copie des éléments à partir de l'original source pour la liste nouvellement créée, donc la seule chose c'est de copier les éléments de la source originale et dépend de la taille source
Compte tenu du rendement de la récupération de la liste de fichiers,
ToList()
est négligeable. Mais pas vraiment pour les autres scénarios. Cela dépend vraiment de l'endroit où vous l'utilisez.Lors de l'appel sur un tableau, une liste, ou d'autres de la collection, vous créez une copie de la collection comme un
List<T>
. La performance dépend de la taille de la liste. Vous devez le faire lorsque c'est vraiment nécessaire.Dans votre exemple, vous appeler sur un tableau. Il parcourt le tableau et ajoute les éléments un par un à une liste nouvellement créée. Donc, l'impact sur la performance dépend du nombre de fichiers.
Lors de l'appel sur une
IEnumerable<T>
, vous matérialiser laIEnumerable<T>
(généralement d'une requête).