2009-07-18 4 views
21

J'utilise .Net 3.5 (C#) et j'ai entendu la performance de C# List<T>.ToArray est "mauvais", car il copie la mémoire pour tous les éléments pour former un nouveau tableau. Est-ce vrai?C# List <T>. La performance de l'Array est mauvaise?

+0

Vous pouvez voir [est-il mieux-to-call-tolist-ou toArray-en-linq- requêtes] (http://stackoverflow.com/questions/1105990/is-it-better-to-call-tolist-or-toarray-in-linq-queries) – nawfal

Répondre

43

Non, ce n'est pas vrai. La performance est bonne car tout ce qu'elle fait, c'est copier la mémoire de tous les éléments (*) pour former un nouveau tableau.

Bien sûr, cela dépend de ce que vous définissez comme "bonne" ou "mauvaise" performance. (*) Références pour les types de référence, valeurs pour les types de valeurs.

EDIT

En réponse à votre commentaire, en utilisant réflecteur est un bon moyen de vérifier la mise en œuvre (voir ci-dessous). Ou réfléchissez juste quelques minutes à la façon dont vous l'implémenterez, et prenez confiance que les ingénieurs de Microsoft ne trouveront pas une solution pire. Bien entendu, les performances "bonnes" ou "mauvaises" n'ont de sens que par rapport à d'autres solutions. Si dans votre cas spécifique, il existe une technique alternative pour atteindre votre objectif qui est sensiblement plus rapide, alors vous pouvez considérer que la performance est «mauvaise». S'il n'y a pas d'alternative, la performance est "bonne" (ou "assez bonne").

EDIT 2

En réponse au commentaire: « Pas de re-construction d'objets?"...

Pas de reconstruction pour les types de référence pour les types de valeurs les valeurs sont copiées, ce qui pourrait vaguement être décrit comme la reconstruction

+2

Merci Joe, votre réponse est tellement cool!Avez-vous des documents connexes pour discuter plus avant ou prouver davantage de la revendication - "tout ce qu'il fait est de copier la mémoire tous les éléments (*) pour former un nouveau tableau."? – George2

+0

Merci Joe, Array.Copiez uniquement la référence de copie? Pas de re-construction d'objets? – George2

+1

George. Allez le chercher! Ou allez utiliser Reflector et découvrez. Ce n'était pas si complexe pour ToArray, n'est-ce pas? –

1

elle crée de nouvelles références dans un tableau, mais qui est juste la seule chose que cette méthode pourrait et devrait faire ...

+0

Vous voulez dire que la référence est copiée? – George2

19

raisons d'appeler ToArray()

  • Si la valeur retournée est pas destiné à être modifié, le retourner comme un tableau rend ce fait un peu plus clair.
  • Si l'appelant doit effectuer de nombreux accès non séquentiels aux données, il peut y avoir un avantage de performance pour un tableau sur une liste <>.
  • Si vous savez que vous devrez transmettre la valeur renvoyée à une fonction tierce qui attend un tableau.
  • Compatibilité avec les fonctions d'appel devant fonctionner avec .NET version 1 ou 1.1. Ces versions n'ont pas le type List (<) (ou tout type générique, d'ailleurs).

Raisons de ne pas appeler ToArray()

  • Si l'appelant ne jamais besoin d'ajouter ou de supprimer des éléments, une liste <> est absolument nécessaire.
  • Les avantages en termes de performances ne sont pas nécessairement garantis, en particulier si l'appelant accède aux données de manière séquentielle. Il y a aussi l'étape supplémentaire de convertir de la liste <> en tableau, ce qui prend du temps de traitement.
  • L'appelant peut toujours convertir lui-même la liste en tableau.

pris de here

+2

Bonne refernece, mais pas de réponse directe à ma question? Quelle est votre réponse à ma question? – George2

+4

C'est la seule réponse que nous pouvons donner: la correction l'emporte toujours sur la performance. Vous n'avez pas la chose la plus performante que vous pouvez qui soit toujours correcte. L'application de cela est que vous n'appelez pas .ToArray() sauf si vous avez de toute façon. –

+4

"... il peut y avoir un avantage de performance pour un tableau sur une liste <>." - Des preuves pour cela? Cela me semble être un mythe. – Joe

1

Performance doit être comprise en termes relatifs Conversion à une liste un tableau consiste à copier la tableau, et le coût de cela dépendra de la taille de la matrice, mais vous devez comparer ce coût à d'autres choses que fait votre programme Comment avez-vous obtenu l'information à mettre dans le tableau en premier lieu? était en lisant à partir du disque, ou une connexion réseau, ou une base de données, puis une copie de tableau en mémoire est très peu susceptible de faire une différence décelable pour le temps pris

+0

"mettre dans le tableau en premier lieu" signifie? – George2

+1

Avant de copier le tableau, vous devez avoir obtenu des informations à stocker dans le tableau, sinon il n'y aurait aucune raison d'en faire une copie. –

4

Oui , c'est vrai qu'il fait une copie mémoire de tous les éléments. Est-ce un problème de performance? Cela dépend de vos exigences de performance. Un List contient un tableau interne pour contenir tous les éléments. Le tableau se développe si la capacité n'est plus suffisante pour la liste. Chaque fois que cela se produit, la liste copiera tous les éléments dans un nouveau tableau. Cela arrive tout le temps, et pour la plupart des gens, ce n'est pas un problème de performance.

E.g. une liste avec un constructeur par défaut commence à la capacité 16, et quand vous .Add() le 17ème élément, il crée un nouveau tableau de taille 32, copie les 16 anciennes valeurs et ajoute le 17ème.

La différence de taille est également la raison pour laquelle ToArray() renvoie une nouvelle instance de tableau au lieu de transmettre la référence privée.

+0

Merci chris166, je veux juste confirmer que seule la référence est copiée pendant ToArray. Pas de re-construction d'objets pendant ToArray? – George2

+1

Oui, seules les références sont copiées. La liste ne sait pas comment créer une copie profonde de vos objets. Les exceptions sont les types de valeur (structs, ints, doubles, enums, etc.). – chris166

0

Pour tout type de List/ICollection où il connaît la longueur, il peut allouer un tableau de la bonne taille depuis le début.

T[] destinationArray = new T[this._size]; 
Array.Copy(this._items, 0, destinationArray, 0, this._size); 
return destinationArray; 

Si votre source est de type IEnumerable (pas une liste/Collection), la source est:

items = new TElement[4]; 
.. 
if (no more space) { 
    TElement[] newItems = new TElement[checked(count * 2)]; 
    Array.Copy(items, 0, newItems, 0, count); 
    items = newItems; 

Il commence au format 4 et croît de façon exponentielle, doublant chaque fois qu'il court d'espace. Chaque fois qu'il double, il doit réallouer la mémoire et copier les données.

Si nous connaissons la taille des données source, nous pouvons éviter cette légère surcharge. Cependant, dans la plupart des cas, par exemple la taille du tableau < = 1024, il s'exécutera si rapidement que nous n'aurons même pas besoin de penser à ce détail d'implémentation.

Références: Enumerable.cs, List.cs (F12ing en eux), la réponse de Joe

Questions connexes