Поделиться через


Потокобезопасные коллекции

В .NET Framework 4 введено пространство имен System.Collections.Concurrent, включающее несколько потокобезопасных и масштабируемых классов коллекций. Несколько потоков могут безопасно и эффективно добавлять и удалять элементы из таких коллекций, не требуя при этом дополнительной синхронизации в пользовательском коде. При написании нового кода пользуйтесь классами параллельных коллекций, когда множество потоков будет вести в коллекцию запись параллельно. Если выполняется только чтение из общей коллекции, вы можете использовать классы в пространстве имен System.Collections.Generic. Мы рекомендуем использовать классы коллекций версии 1.0 только в том случае, если вам нужна среда выполнения .NET Framework до версии 1.1 включительно.

Синхронизация потоков в коллекциях .NET Framework версий 1.0 и 2.0

Коллекции, представленные в .NET Framework 1.0, находятся в пространстве имен System.Collections. Эти коллекции, которые содержат часто используемые классы ArrayList и Hashtable, обеспечивают определенную степень потокобезопасности посредством свойства Synchronized, которое создает для коллекции потокобезопасную программу-оболочку. Работа программы оболочки заключается в блокировке всей коллекции при каждой операции добавления или удаления. Поэтому каждый поток, который пытается получить доступ к коллекции, должен ждать своей очереди для получения блокировки. Такой подход не является масштабируемым и может привести к значительному снижению производительности для больших коллекций. Также такой подход не защищен полностью от состояния гонки. Дополнительные сведения см. в статье Синхронизация в универсальных коллекциях.

Классы коллекций, представленные в .NET Framework 2.0, находятся в пространстве имен System.Collections.Generic. К ним относятся List<T>, Dictionary<TKey,TValue> и др. Эти классы отличаются улучшенной безопасностью типа и производительностью по сравнению с классами .NET Framework 1.0. Однако классы коллекций .NET Framework 2.0 не обеспечивают синхронизацию потоков. Пользовательский код должен обеспечивать всю синхронизацию при параллельном добавлении элементов в несколько потоков или удалении элементов из них.

Рекомендуем использовать классы многопоточных коллекций .NET Framework 4, так как они обеспечивают не только безопасность типа, как у классов .NET Framework 2.0, но и большую эффективность и более полную потокобезопасность по сравнению с коллекциями .NET Framework 1.0.

Механизм блокировки мелких фрагментов данных и механизм, свободный от блокировки

Некоторые типы многопоточных коллекций используют упрощенные механизмы синхронизации, например SpinLock, SpinWait, SemaphoreSlim и CountdownEvent, которые впервые введены в .NET Framework 4. Эти типы синхронизации обычно используют цикличную работу для коротких промежутков перед помещением потока в фактическое состояние ожидания. При условии, что время ожидания предполагается очень коротким, цикличность требует значительно меньших затрат компьютерных ресурсов, чем ожидание, которое включает в себя переход в режим ядра, требующий больших затрат компьютерных ресурсов. Для классов коллекций, которые используют цикличность, эта эффективность означает, что множество потоков могут добавлять и удалять большое количество элементов. Дополнительные сведения о цикличности и блокировках см. в статья SpinLock и SpinWait.

Классы ConcurrentQueue<T> и ConcurrentStack<T> не используют блокировку. Вместо этого они используют операции класса Interlocked для обеспечения потокобезопасности.

Примечание

Так как классы многопоточных коллекций поддерживают интерфейс ICollection, они включают реализации для свойств IsSynchronized и SyncRoot, даже хотя эти свойства никак не используются. IsSynchronized всегда возвращает false, а SyncRoot всегда имеет значение null (Nothing в Visual Basic).

В следующей таблице перечислены типы коллекций в пространстве имен System.Collections.Concurrent.

Type Описание
BlockingCollection<T> Предоставляет возможности блокировки и ограничения для всех типов, реализующих интерфейс IProducerConsumerCollection<T>. Дополнительные сведения см. в разделе Общие сведения о коллекции BlockingCollection.
ConcurrentDictionary<TKey,TValue> Потокобезопасная реализация словаря пар "ключ-значение".
ConcurrentQueue<T> Потокобезопасная реализация очереди с типом "первым поступил — первым обслужен" (FIFO).
ConcurrentStack<T> Потокобезопасная реализация стека с типом "последним поступил — первым обслужен" (LIFO).
ConcurrentBag<T> Потокобезопасная реализация неупорядоченной коллекции элементов.
IProducerConsumerCollection<T> Это интерфейс, тип которого должен быть реализован для использования в классе BlockingCollection.
Заголовок Описание
Общие сведения о коллекции BlockingCollection Приводится описание функциональных возможностей, которые предоставляются типом BlockingCollection<T>.
Практическое руководство. Добавление элементов в коллекцию ConcurrentDictionary и их удаление из этой коллекции Приводится описание добавления и удаления элементов в классе ConcurrentDictionary<TKey,TValue>
Практическое руководство. Добавление и удаление отдельных элементов коллекции BlockingCollection Приводится описание порядка добавления и получения элементов из заблокированной коллекции без использования перечислителя, доступного только для чтения.
Практическое руководство. Добавление функций границы и блокировки в коллекцию Приводится описание порядка использования всех классов коллекций в качестве базового механизма хранения для коллекции IProducerConsumerCollection<T>.
Практическое руководство. Использование оператора ForEach для удаления элементов в коллекции BlockingCollection Описание порядка использования foreach (For Each в Visual Basic) для удаления всех элементов в заблокированной коллекции.
Практическое руководство. Использование массивов для блокировки коллекций в конвейере Приводится описание порядка одновременного использования нескольких заблокированных коллекций для реализации конвейера.
Практическое руководство. Создание пула объектов с помощью класса ConcurrentBag Показано, как применить параллельный контейнер для повышения производительности в сценариях, где можно повторно использовать объекты вместо постоянного создания новых.

Справочник

System.Collections.Concurrent