Pull to refresh

Comments 12

Hе совсем уловил смысл.
Цикл вывел 17 элементов, тогда почему Вы указали, что:
17 элемент в коллекцию был вставлен успешно, но итератор его не увидел, почему
.
Может быть 18-ый элемент.
И почему именно столько элементов получилось?
Да, 18 элемент, спасибо, поправил.
Увеличение размера массива в ConcurrentDictionary происходит, если количество элементов в одном из связных списков превысит разрешенное количество элементов на 1 lock. Это значение получается так: m_budget = m_tables.m_buckets.Length / m_tables.m_locks.Length; где m_tables.m_buckets — массив односвязных списков, m_tables.m_locks — массив с объектами для блокировок (размер этого массива по умолчанию равен число_процессоров*4)
Я прошу прощения, бездумно взял ответ на ваш вопрос с ресурса , и там сказано следующее: the buckets array has to be resized once the number of items in each bucket has gone over a certain limit. (In ConcurrentDictionary this limit is when the size of the largest bucket is greater than the number of buckets for each lock. This check is done at the end of the TryAddInternal method.). Но это ошибочное утверждение.
Правильно будет так: размер коллекции изменяется, когда количество элементов на одну блокировку превышает превышает значение m_budget.
На моем примере: у меня 4 процессора, соответственно размер массива m_locks = 16, а m_budget = 31/16 = 1. Как только мы вставляем 17 элемент, на одну блокировку теперь приходится 2 элемента и коллекция расширяется.
Постараюсь описать этот момент более подробно и включу в статью.
Лучше всего придерживаться правила описанного на MSDN, что внесенные изменения могут быть видны, а могут и нет.
Лучше всего «не изменять коллекцию во время перебора».
А как вы это можете гарантировать в случае многопоточной среды? Брать lock перед каждым циклом foreach не самое удачное решение на мой взгляд.
Сложно мне представить такую ситуацию, чтобы множество потоков единовременно прогоняло один и тот же словарь.
Ну представим на минуту, что у нас есть именно такая задача, хочу понять как и главное зачем вы предлагаете обеспечивать требование «не изменять коллекцию во время перебора»?
Вот не люблю такие гипотетические ситуации, оторванные от практики. Я бы сказал, что вы неправильно ставите вопрос. Назовите реальную практическую проблему, при решении которой возникла такая ситуация, тогда можно будет уже предметно говорить.
Хорошо, вот пример. Есть несколько FileSystemWatcher'ов которые следят за несколькими папками и добавляют url файлов в ConcurrentDictionary, в другом потоке происходит перебор словаря и данные из него удаляются. Допустим в каждую папку падает до нескольких тысяч файлов в секунду. Учтем то, что время обработки события появления нового файла должно стремиться к 0, иначе мы получим переполнение внeтреннего буфера FileSystemWatcher'a.
Дополнительное условие не предлагать переделать на ConcurrentQueue или другую коллекцию, а рассматривать задачу именно так как она описана.
1)
Учтем то, что время обработки события появления нового файла должно стремиться к 0, иначе мы получим переполнение внeтреннего буфера FileSystemWatcher'a.
А у вашего ConcurrentDictionary переполнения быть не может?

2)
Дополнительное условие не предлагать переделать на ConcurrentQueue или другую коллекцию, а рассматривать задачу именно так как она описана.
Перефразирую: «У меня тут кривая архитектура, всё не работает, подскажите, как лучше? P.S. нельзя ничего менять». Гипертрофированный пример.
1) Разве что OutOfMemoryException.
Это условие я добавил лишь для того, чтобы показать, что блокировать коллекцию на время перебора в данном случае невозможно, иначе рискуем потеряем часть данных.
2) Ничего подсказывать не нужно, я просто привел пример из своего опыта, хоть и немного притянутый за уши. (Задача давно решена, и она легко решается с использованием ConcurrentQueue, но пример с данной коллекцией не подойдет для обсуждения текущего вопроса, поэтому я попросил не использовать ее)
Я просто просил объяснения зачем запрещать изменять коллекцию на время перебора, вдруг я чего-то не понимаю, и мне не важно на каком вы примере это сделаете — моем, своем, или каком-то абстрактом. Вы почему-то слишком негативно настроены и придираетесь к деталям, хотя я просто просил пояснения.
Я не придираюсь, а лишь просил практический пример. Вы же привели пример с неправильной архитектурой на ConcurrentDictionary, ввели искусственное ограничение. Но, в то же время, затем сами же сказали, что переписали на ConcurrentQueue.
Что возвращает нас к изначальному вопросу о примере, где реально необходимо использовать ConcurrentDictionary в многопоточной среде.
Sign up to leave a comment.

Articles