Потокобезопасный доступ к статической коллекции - PullRequest
2 голосов
/ 11 ноября 2011

Я создаю класс, который будет иметь какое-либо соединение ключ-значение. В настоящее время у меня есть что-то похожее на следующее:

private static Dictionary<Type, List<PropertyInfo>> PropertyCache { get; set; }

Это правильный способ реализации в поточно-ориентированном подходе? По какой-то причине меня беспокоит эффект static на Dictionary в этом случае. Если это правильно, есть ли неправильный способ, который можно продемонстрировать, чтобы я мог избежать этого в остальной части моего кода.

Кроме того, должен ли он быть только для чтения (я только собираюсь добавлять или удалять вещи из коллекции)?

Если это имеет значение, свойство всегда будет объявлено private.

Заранее спасибо

Несмотря на пометку C #, ответы на VB в порядке, я, так сказать, "двуязычный"

EDIT:

После обсуждения с Джоном Скитом в комментариях к его ответу, использование будет:

// I will do this
PropertyCache.Add(typeof(string), new List<PropertyInfo>());
PropertyCache.Remove(typeof(string));

// I will never do this 
PropertyCache = new Dictionary<Type, List<PropertyInfo>>();

Я никогда не буду перебирать коллекцию, только доступ по ключу.

Ответы [ 3 ]

3 голосов
/ 11 ноября 2011

Вам, вероятно, следует сделать его доступным только для чтения, если только вам не понадобится изменять значение переменной, да.

Если вы используете .NET 4, вам следует рассмотреть возможность использования ConcurrentDictionary - иначе, я бы, вероятно, написал аксессоры, которые просто получают блокировку для каждого доступа.В то время как вы могли бы использовать ReaderWriterLockSlim и т. Д., Лично я бы пошел с самого простого безопасного подхода для начала.

Обратите внимание, что итерация содержимого словаря потокобезопасным способомбудет сложно - надеюсь, вам это не нужно.

1 голос
/ 11 ноября 2011

Создание элемента static повышает вероятность наличия многопоточного доступа, чем члена экземпляра.Помните, что static не означает, что что-то безопасно для использования несколькими потоками, это означает, что объект совместно используется несколькими экземплярами объекта, в котором он определен.

Коллекции, которые реализуют интерфейс ICollectionможно привести к SyncRoot, который можно использовать к lock объекту, чтобы гарантировать, что только один поток за раз может выполнить серию инструкций, которые могут привести к изменению коллекции. Использование SyncRoot для многопоточных приложений

lock(((ICollection)myObject).SyncRoot)
{
    //Code that should be executed by only one concurrent thread
    //This is add/insert/remove/iterate/clear/etc.
}

В дополнение к этому руководству (или в старшей школе) в .NET 4 доступны параллельные объекты, которые делают это в основном, но с некоторыми другими специальнымичеки.По большей части эти объекты оптимизированы по производительности настолько, насколько это возможно для полностью безопасных объектов.Если вы используете очень контролируемый и небольшой набор действий над объектом (у вас есть 1 метод add, 1 метод удаления и вы никогда не перечисляете всю коллекцию, а просто получаете доступ к определенным, известным записям), вы можете использовать более легкий пример lock()выше, чтобы повысить производительность.

Это особенно заметно при добавлении нескольких объектов в коллекцию одновременно.Используя параллельные объекты, каждая операция Add является атомарной с блокировкой и разблокировкой.Если вы выполняете это в тесном цикле, вы теряете немного производительности из-за получения блокировок снова и снова.Если другой поток пытается прочитать, конкуренция за доступ становится немного выше.Если вы сами используете оператор блокировки, вы можете просто получить блокировку, добавить объекты в быстрый и плотный цикл, а затем снять блокировку.Потоки, желающие получить доступ к объекту, будут ждать немного дольше, но в целом операции должны завершаться быстрее.Также имейте в виду, что различия, как правило, настолько малы, что на самом деле это не стоит, и почти во всех случаях подпадают под категорию преждевременной оптимизации.

0 голосов
/ 11 ноября 2011

То, что вы показали, никоим образом не безопасно для потоков. Если несколько потоков могут вставлять или удалять элементы одновременно, у вас есть потенциальная проблема.

...