Я столкнулся с интересной проблемой. Зная, что ConcurrentDictionary<TKey, TValue>
можно безопасно перечислить при изменении, с (в моем случае) нежелательным побочным эффектом перебора элементов, которые могут исчезать или появляться несколько раз, я решил создать снимок самостоятельно, используя ToList()
. Поскольку ConcurrentDictionary<TKey, TValue>
также реализует ICollection<KeyValuePair<TKey, TValue>>
, это приводит к использованию List(IEnumerable<T> collection)
, который, в свою очередь, создает массив текущего размера словаря, используя текущий элемент Count
, затем пытается скопировать элементы using ICollection<T>.CopyTo(T[] array, int arrayIndex)
, вызывая его реализацию ConcurrentDictionary<TKey, TValue>
, и, наконец, бросая ArgumentException
, если элементы тем временем добавляются в словарь.
Полная блокировка убьет смысл использования коллекции как таковой, поэтому мои варианты, похоже, заключаются в том, чтобы либо продолжать перехватывать исключение и повторять попытку (что определенно не является правильным решением проблемы), либо реализовать мою собственную версию ToList()
специализированный для этой проблемы (но опять же, простое увеличение списка, а затем, возможно, его обрезка до нужного размера для нескольких элементов кажется излишним, а использование LinkedList снизит производительность индексации).
Кроме того, кажется, что добавление определенных методов LINQ, создающих какой-то буфер в фоновом режиме (например, OrderBy
), кажется, решает проблему за счет производительности, но голый ToList()
явно этого не делает, да и не стоит" дополняя его другим методом, когда дополнительные функции не требуются.
Может ли это быть проблемой с какой-либо параллельной коллекцией?
Что было бы разумным обходным путем, чтобы свести к минимуму потери производительности при создании такого моментального снимка? (Желательно в конце некоторой магии LINQ.)
Изменить:
Изучив его, я могу подтвердить, ToArray()
(думать, что я только что прошел мимо него вчера) действительно решает проблему снимка, если это просто простой снимок, он не помогает, когда требуются дополнительные функции, прежде чем сделать указанный снимок (например, фильтрация, сортировка), и список/массив по-прежнему необходим в конце. (В этом случае требуется дополнительный вызов, создающий новую коллекцию заново.)
Я не указал, что моментальный снимок может нуждаться или не нуждаться в этих модификациях, поэтому желательно, чтобы он был сделан в конце, поэтому я бы добавил это к вопросам.
(Кроме того, если у кого-то есть лучшая идея для названия, скажите.)
.ToArray()
, который реализован специально для типа. - person Lasse V. Karlsen   schedule 08.12.2016