openclassroom - msdn c# dictionary




Capacité initiale des types de collection, par exemple Dictionnaire, Liste (3)

Certains types de collection dans .Net ont un paramètre de constructeur facultatif "Initial Capacity". 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 fixer la capacité initiale à quelque chose comme 20?

Mon raisonnement est, en supposant que la capacité croît comme 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 qui contiendra vos données, avec un peu plus chambre juste au cas où? Si la capacité initiale est de 100, et je sais que je n'aurai besoin que d'une douzaine, il semble que le reste de cette mémoire ne soit alloué à rien.


En vérifiant la source, la capacité par défaut pour List<T> et Dictionary<TKey, TValue> est 0.


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

Les surcharges de constructeur avec une capacité concernent les cas dans lesquels vous connaissez 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, elle ne devra donc pas être 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 aussi les versions précédentes),

  • une liste <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 dictionnaire <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.


Un autre problème avec 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 tests que j'ai essayés.

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

C'est-à-dire que lorsque la taille initiale est spécifiée, cela ne fait rien pour augmenter la vitesse de ConcurrentDictionary lors de l'ajout d'objets. Techniquement, je pense que cela devrait être le cas, car il ne faut pas forcément du temps ou des ressources pour se redimensionner.

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

Donc, la morale de l'histoire est que la taille initiale ne garantit pas toujours une amélioration des performances.





object-initializers