У меня возникла интересная проблема. Зная, что 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() на ConcurrentDictionary <TKey, TValue> при добавлении элементов
Блокировка на всем уровне будет убивать точку использования коллекции, так как мои параметры, похоже, либо должны улавливать исключение и повторять попытку (что определенно не является правильным ответом на проблему), либо реализовать мои собственная версия ToList()
, специализирующаяся на этой проблеме (но опять же, просто увеличивая список, а затем, возможно, подрезая его до нужного размера, для нескольких элементов кажется излишним, а использование LinkedList уменьшит производительность индексации).
Кроме того, похоже, добавив некоторые методы LINQ, которые создают своего рода буфер в фоновом режиме (например, как OrderBy
), кажется, исправить эту проблему за счет производительности, но голый ToList()
явно не делает, и это не стоит «дополнять» его другим методом, если не требуется никаких дополнительных функций.
Это может быть проблема с любой параллельной коллекцией?
Каково было бы разумное обходное решение, позволяющее свести производительность до минимума при создании такого моментального снимка? (Предпочтительно в конце некоторого LINQ магии.)
Edit:
Посмотрев на него, я могу подтвердить, ToArray()
(думать, что я просто проходил мимо него вчера) действительно решить проблему моментальных снимков, как поскольку это просто, простой снимок, это не помогает, когда требуется дополнительная функциональность, прежде чем принимать указанный снимок (например, фильтрацию, сортировку), а список/массив по-прежнему необходим в конце. (В этом случае требуется дополнительный вызов, снова создавая новую коллекцию.)
Я не указал, что для моментального снимка может потребоваться или не понадобиться выполнить эти изменения, поэтому его следует принять на конечно, поэтому я бы добавил это к вопросам.
(Кроме того, если кто-нибудь имеют лучшую идею для названия, не говорят.)
Используйте '.ToArray()' вместо этого, который реализуется специально по типу. –