J'ai rencontré un problème intéressant. Sachant que le ConcurrentDictionary<TKey, TValue>
est enumerable en toute sécurité en étant modifié, avec (dans mon cas) un effet secondaire indésirable d'itération sur les éléments qui peuvent disparaître ou apparaître plusieurs fois, j'ai décidé de créer moi-même un snapshot en utilisant ToList()
. Comme ConcurrentDictionary<TKey, TValue>
implémente également ICollection<KeyValuePair<TKey, TValue>>
, cela provoque l'utilisation du List(IEnumerable<T> collection)
, qui à son tour crée un tableau dans la taille actuelle du dictionnaire en utilisant l'élément actuel Count
, puis tente de copier les éléments using ICollection<T>.CopyTo(T[] array, int arrayIndex)
, appelant dans son implémentation ConcurrentDictionary<TKey, TValue>
, et enfin lancer un ArgumentException
si des éléments sont ajoutés au dictionnaire entre-temps. En verrouillant tout cela, l'option d'utilisation de la collection serait supprimée, donc mes options semblent être soit de continuer à attraper l'exception et de réessayer (ce qui n'est certainement pas la bonne réponse au problème), soit d'implémenter mon propre version de ToList()
spécialisée pour ce problème (mais encore une fois, en augmentant simplement une liste, puis en l'ajustant à la bonne taille pour quelques éléments semble être une surcharge, et en utilisant une LinkedList diminuerait les performances d'indexation). En outre, il semble que l'ajout de certaines méthodes LINQ qui créent une sorte de tampon en arrière-plan (comme OrderBy
) semble améliorer le problème au détriment de la performance, mais il est évident que le ToList()
nu ne le fait pas, et il ne vaut pas la peine de "l'augmenter" avec une autre méthode lorsqu'aucune fonctionnalité supplémentaire n'est nécessaire.Appel de ToList() sur ConcurrentDictionary <TKey, TValue> lors de l'ajout d'éléments
Cela peut-il être un problème avec une collection simultanée?
Quelle serait une solution de contournement raisonnable pour maintenir les performances atteintes au minimum lors de la création d'un tel instantané? (De préférence à la fin de la magie LINQ.)
Edit:
Après avoir examiné ce que je peux confirmer, ToArray()
(penser que je viens de passer par hier) fait vraiment résoudre le problème de l'instantané comme Bien que ce soit juste un instantané simple, cela n'aide pas lorsque des fonctionnalités supplémentaires sont nécessaires avant de prendre l'instantané (comme le filtrage, le tri), et une liste/tableau est toujours nécessaire à la fin. (Dans ce cas, un appel supplémentaire est nécessaire, créant à nouveau la nouvelle collection.)
Je n'ai pas indiqué que l'instantané peut ou ne doit pas subir ces modifications, il doit donc être pris à la fin, de préférence, donc j'ajouterais cela aux questions.
(Aussi, si quelqu'un a une meilleure idée pour un titre, ne le dire.)
Utilisez plutôt '.ToArray()' qui est implémenté spécifiquement par le type. –