web-dev-qa-db-fra.com

Capacité initiale des types de collecte, par ex. Dictionnaire, Liste

Certains types de collection dans .Net ont un paramètre de constructeur facultatif "Capacité initiale". Par exemple:

Dictionary<string, string> something = new Dictionary<string,string>(20);

List<string> anything = new List<string>(50);

Je n'arrive pas à trouver quelle est la capacité initiale par défaut pour ces objets sur MSDN.

Si je sais que je ne stockerai qu'une douzaine d'éléments dans un dictionnaire, n'est-il pas logique de définir la capacité initiale sur quelque chose comme 20?

Mon raisonnement est, en supposant que la capacité augmente comme elle le fait pour un StringBuilder, qui double chaque fois que la capacité est atteinte, et que chaque réallocation est coûteuse, pourquoi ne pas prédéfinir la taille à quelque chose que vous savez qu'il contiendra vos données, avec un peu plus chambre juste au cas où? Si la capacité initiale est de 100 et que je sais que je n'en aurai besoin que d'une douzaine, il semble que le reste de cette mémoire soit alloué pour rien.

39
Neil N

Si les valeurs par défaut ne sont pas documentées, il est probable que la capacité initiale optimale soit un détail de l'implémentation et sujette à changement entre les versions du framework. Autrement dit, vous ne devez pas écrire de code qui suppose une certaine valeur par défaut.

Le constructeur les surcharges avec une capacité sont pour les cas où vous savez mieux que la classe le nombre d'éléments à prévoir. Par exemple, si vous créez une collection de 50 valeurs et que vous savez que ce nombre n'augmentera jamais, vous pouvez initialiser la collection avec une capacité de 50, afin qu'elle ne soit pas redimensionnée si la capacité par défaut est inférieure.

Cela dit, vous pouvez déterminer les valeurs par défaut à l'aide de Reflector. Par exemple, dans .NET 4.0 (et probablement dans les versions précédentes également),

  • une List <T> est initialisée avec une capacité de 0. Lorsque le premier élément est ajouté, il est réinitialisé à une capacité de 4. Par la suite, chaque fois que la capacité est atteinte, la capacité est doublée.

  • un Dictionary <T> est également initialisé avec une capacité de 0. Mais il utilise un algorithme complètement différent pour augmenter la capacité: il augmente toujours la capacité aux nombres premiers.

72
dtb

Vérification de la source, capacité par défaut pour les deux List<T> et Dictionary<TKey, TValue> vaut 0.

9
SLaks

Si vous connaissez la taille, dites-le; une optimisation mineure dans la plupart des "petits" cas, mais utile pour les grandes collections. Je voudrais principalement m'inquiéter à ce sujet si je jette une quantité "décente" de données, car cela peut alors éviter d'avoir à allouer, copier et collecter plusieurs tableaux.

La plupart des collections utilisent en effet une stratégie de doublement.

9
Marc Gravell

Un autre problème avec le ConcurrentDictionary (actuellement) et l'utilisation de son constructeur pour définir une taille initiale est que ses performances semblent être entravées.

Par exemple, voici quelques exemples de code et de référence J'ai essayé.

J'ai exécuté le code sur ma machine et j'ai obtenu des résultats similaires.

Autrement dit, lorsque la taille initiale est spécifiée, cela ne fait rien pour augmenter la vitesse du ConcurrentDictionary lors de l'ajout d'objets. Techniquement, je pense qu'il devrait car il n'a pas besoin de temps ou de ressources pour se redimensionner.

Oui, il peut ne pas fonctionner aussi vite qu'un dictionnaire normal, mais je m'attendrais toujours à ce qu'un ConcurrentDictionary avec sa taille initiale définie ait des performances cohérentes et plus rapides qu'un ConcurrentDictionary qui n'a pas sa taille initiale définie, surtout quand on sait à l'avance le nombre d'éléments qui y seront ajoutés.

La morale de l'histoire est donc de définir la taille initiale ne garantit pas toujours une amélioration des performances.

2
user3810913