176 votes

L'appel à ToList() a-t-il un impact sur les performances ?

Lors de l'utilisation de ToList() L'impact sur les performances doit-il être pris en compte ?

J'écrivais une requête pour extraire des fichiers d'un répertoire, qui est la requête :

string[] imageArray = Directory.GetFiles(directory);

Cependant, comme j'aime travailler avec des List<> Au lieu de cela, j'ai décidé de mettre en...

List<string> imageList = Directory.GetFiles(directory).ToList();

Y a-t-il donc un impact sur les performances à prendre en compte lorsque l'on décide d'effectuer une telle conversion - ou seulement lorsque l'on a affaire à un grand nombre de fichiers ? S'agit-il d'une conversion négligeable ?

214voto

Daniel Imms Points 16273

IEnumerable<T>.ToList()

Oui, IEnumerable<T>.ToList() a un impact sur les performances, il s'agit d'une O(n) Bien qu'il ne doive être pris en compte que dans le cadre d'opérations critiques en termes de performances, il est probable qu'il ne soit pas nécessaire d'y prêter attention.

En ToList() utilisera l'opération List(IEnumerable<T> collection) constructeur. Ce constructeur doit faire une copie du tableau (plus généralement IEnumerable<T> ), sinon les modifications futures du tableau original changeront sur la source T[] ce qui n'est pas souhaitable d'une manière générale.

Je tiens à rappeler que cela ne fera une différence qu'avec une liste volumineuse, la copie de morceaux de mémoire étant une opération assez rapide à réaliser.

Conseil pratique, As vs To

Vous remarquerez qu'il existe dans LINQ plusieurs méthodes qui commencent par As (par exemple AsEnumerable() ) et To (par exemple ToList() ). Les méthodes qui commencent par To nécessitent une conversion comme ci-dessus (c'est-à-dire qu'elles peuvent avoir un impact sur les performances), et les méthodes qui commencent par As ne le font pas et ne nécessiteront qu'un moulage ou une opération simple.

Plus d'informations sur List<T>

Voici un peu plus de détails sur la façon de procéder List<T> fonctionne en cas d'intérêt :)

A List<T> utilise également une construction appelée tableau dynamique qui doit être redimensionné à la demande, cet événement de redimensionnement copie le contenu d'un ancien tableau dans le nouveau tableau. Il commence donc par être petit et s'agrandit si nécessaire .

C'est la différence entre le Capacity y Count propriétés sur List<T> . Capacity fait référence à la taille du tableau dans les coulisses, Count est le nombre d'éléments dans le List<T> qui est toujours <= Capacity . Ainsi, lorsqu'un élément est ajouté à la liste, le fait de l'augmenter au-delà de Capacity , la taille de la List<T> est doublée et le tableau est copié.

42voto

Danny Chen Points 14781

L'appel à toList() a-t-il un impact sur les performances ?

Oui, bien sûr. En théorie, même i++ a un impact sur les performances, il ralentit le programme pendant quelques ticks.

Qu'est-ce que .ToList faire ?

Lorsque vous invoquez .ToList le code appelle Enumerable.ToList() qui est une méthode d'extension que return new List<TSource>(source) . Dans le constructeur correspondant, dans les pires circonstances, il parcourt le conteneur d'éléments et les ajoute un par un dans un nouveau conteneur. Son comportement a donc peu d'incidence sur les performances. Il est impossible d'être un goulot d'étranglement pour les performances de votre application.

Qu'est-ce qui ne va pas dans le code de la question ?

Directory.GetFiles parcourt le dossier et renvoie les noms de tous les fichiers immédiatement en mémoire, il y a un risque potentiel que la chaîne[] coûte beaucoup de mémoire, ce qui ralentit tout.

Que faire alors ?

Cela dépend. Si vous (ainsi que votre logique commerciale) garantissez que la quantité de fichiers dans le dossier est toujours faible, le code est acceptable. Mais il est toujours conseillé d'utiliser une version paresseuse : Directory.EnumerateFiles en C#4. Cela ressemble beaucoup plus à une requête, qui ne sera pas exécutée immédiatement, vous pouvez y ajouter d'autres requêtes comme :

Directory.EnumerateFiles(myPath).Any(s => s.Contains("myfile"))

qui arrêtera recherche le chemin dès qu'un fichier dont le nom contient "monfichier" est trouvé. Cette méthode est évidemment plus performante que .GetFiles .

23voto

Martin Liversage Points 43712

L'appel à toList() a-t-il un impact sur les performances ?

Oui, c'est le cas. En utilisant la méthode de l'extension Enumerable.ToList() construira un nouveau List<T> de l'objet IEnumerable<T> ce qui a bien sûr un impact sur les performances.

Cependant, la compréhension List<T> peut vous aider à déterminer si l'impact sur les performances est significatif.

List<T> utilise un tableau ( T[] ) pour stocker les éléments de la liste. Les tableaux ne peuvent pas être étendus une fois qu'ils sont alloués. List<T> utilisera un tableau surdimensionné pour stocker les éléments de la liste. Lorsque le tableau List<T> dépasse la taille du tableau sous-jacent, un nouveau tableau doit être alloué et le contenu de l'ancien tableau doit être copié dans le nouveau tableau plus grand avant que la liste ne puisse s'allonger.

Lorsqu'un nouveau List<T> est construit à partir d'un IEnumerable<T> il y a deux cas de figure :

  1. La collection de sources met en œuvre ICollection<T> : Alors ICollection<T>.Count est utilisé pour obtenir la taille exacte de la collection source et un tableau d'appui correspondant est alloué avant que tous les éléments de la collection source soient copiés dans le tableau d'appui à l'aide de la fonction ICollection<T>.CopyTo() . Cette opération est assez efficace et correspondra probablement à une instruction de l'unité centrale permettant de copier des blocs de mémoire. Cependant, en termes de performances, il faut de la mémoire pour le nouveau tableau et des cycles de l'unité centrale pour copier tous les éléments.

  2. Dans le cas contraire, 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, au nouveau fichier List<T> . Au départ, le tableau d'appui est vide et un tableau de taille 4 est créé. Ensuite, lorsque ce tableau est trop petit, sa taille est doublée, de sorte que le tableau d'appui croît comme suit : 4, 8, 16, 32, etc. Chaque fois que le tableau d'appui grandit, il doit être réalloué et tous les éléments stockés jusqu'à présent doivent être copiés. Cette opération est beaucoup plus coûteuse que dans le premier cas, où un tableau de taille correcte peut être créé immédiatement.

    De plus, si votre collection source contient par exemple 33 éléments, la liste finira par utiliser un tableau de 64 éléments, ce qui gaspille de la mémoire.

Dans votre cas, la collection source est un tableau qui met en œuvre la fonction ICollection<T> l'impact sur les performances n'est donc pas à craindre, à moins que votre tableau source ne soit très grand. Appel ToList() copiera simplement le tableau source et l'enveloppera dans un fichier List<T> objet. Même les performances du deuxième cas ne sont pas préoccupantes pour les petites collections.

5voto

Haris Hasan Points 17497

ToList() crée une nouvelle liste et y place les éléments, ce qui signifie qu'il y a un coût associé à cette opération. ToList() . Dans le cas d'une petite collection, le coût n'est pas très perceptible, mais l'utilisation de ToList dans le cas d'une grande collection peut entraîner une baisse des performances.

En règle générale, vous ne devez pas utiliser ToList(), sauf si le travail que vous effectuez ne peut être réalisé sans convertir la collection en liste. Par exemple, si vous souhaitez simplement parcourir la collection, il n'est pas nécessaire d'utiliser ToList

Si vous effectuez des requêtes sur une source de données, par exemple une base de données, en utilisant LINQ to SQL, le coût de l'utilisation de ToList est beaucoup plus élevé car lorsque vous utilisez ToList avec LINQ to SQL, au lieu de procéder à une exécution différée, c'est-à-dire de charger les éléments lorsque cela est nécessaire (ce qui peut être bénéfique dans de nombreux scénarios), il charge instantanément les éléments de la base de données dans la mémoire.

3voto

MD.Unicorn Points 8354

Considérer la performance de l'extraction de la liste des fichiers, ToList() est négligeable. Mais pas vraiment pour d'autres scénarios. Cela dépend vraiment de l'endroit où vous l'utilisez.

  • Lorsque vous faites appel à un tableau, une liste ou une autre collection, vous créez une copie de la collection sous la forme d'un fichier List<T> . Les performances dépendent de la taille de la liste. Vous ne devez le faire que lorsque c'est vraiment nécessaire.

    Dans votre exemple, vous l'appelez sur un tableau. Il itère sur le tableau et ajoute les éléments un par un à une liste nouvellement créée. L'impact sur les performances dépend donc du nombre de fichiers.

  • Lorsque l'on fait appel à un IEnumerable<T> , vous se matérialiser les IEnumerable<T> (généralement une requête).

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