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


Структуры данных для параллельного программирования

.NET предоставляет несколько типов, которые полезны в параллельном программировании, включая набор параллельных классов коллекций, простые примитивы синхронизации и типы для отложенной инициализации. Эти типы можно использовать с любым многопоточным кодом приложения, включая библиотеку параллельных задач и PLINQ.

Классы параллельных коллекций

Классы коллекций в пространстве имен System.Collections.Concurrent предоставляют потокобезопасные операции добавления и удаления, которые позволяют избежать блокировок, где это возможно, и используют мелкозернистое блокирование там, где блокировки необходимы. Для параллельного класса коллекции не требуется использовать пользовательский код для блокировки при доступе к элементам. Классы параллельной коллекции могут значительно повысить производительность таких типов, как System.Collections.ArrayList и System.Collections.Generic.List<T> (с блокировкой, реализованной пользователем) в сценариях, когда несколько потоков добавляют и удаляют элементы из коллекции.

В следующей таблице перечислены параллельные классы коллекции:

Тип Описание
System.Collections.Concurrent.BlockingCollection<T> Предоставляет возможности блокировки и ограничения для потоково-безопасных коллекций, реализующих System.Collections.Concurrent.IProducerConsumerCollection<T>. Потоки производителя блокируются, если слоты недоступны или если коллекция заполнена. Потоки потребителей останавливаются, если коллекция пуста. Этот тип также поддерживает неблокирующий доступ потребителей и производителей. BlockingCollection<T> можно использовать в качестве базового класса или резервного хранилища, чтобы обеспечить блокировку и привязку для любого класса коллекции, поддерживающего IEnumerable<T>.
System.Collections.Concurrent.ConcurrentBag<T> Реализация пакета, безопасная для потоков, которая предоставляет масштабируемые операции добавления и получения.
System.Collections.Concurrent.ConcurrentDictionary<TKey,TValue> Одновременный и масштабируемый словарь.
System.Collections.Concurrent.ConcurrentQueue<T> Одновременная и масштабируемая очередь FIFO.
System.Collections.Concurrent.ConcurrentStack<T> Параллельный и масштабируемый стек LIFO.

Дополнительные сведения см. в разделе Thread-Safe Коллекции.

Примитивы синхронизации

Примитивы синхронизации в пространстве имен System.Threading обеспечивают гранулированную параллелизацию и более быструю производительность, избегая дорогостоящих механизмов блокировки, найденных в устаревшем многопотоковом коде.

В следующей таблице перечислены типы синхронизации:

Тип Описание
System.Threading.Barrier Позволяет нескольким потокам работать с алгоритмом параллельно, предоставляя точку, в которой каждая задача может сигнализировать о своем прибытии, а затем блокироваться до тех пор, пока некоторые или все задачи не прибудут. Дополнительные сведения см. в разделе "Барьер".
System.Threading.CountdownEvent Упрощает сценарии разветвления и объединения, предоставляя простой механизм синхронизации. Дополнительные сведения см. в разделе CountdownEvent.
System.Threading.ManualResetEventSlim Примитив синхронизации аналогичен System.Threading.ManualResetEvent. ManualResetEventSlim имеет более легкий вес, но может использоваться только для внутрипроцессного взаимодействия.
System.Threading.SemaphoreSlim Примитив синхронизации, ограничивающий количество потоков, которые могут одновременно получать доступ к ресурсу или пулу ресурсов. Дополнительные сведения см. в разделе Semaphore и SemaphoreSlim.
System.Threading.SpinLock Примитив взаимного исключения, заставляющий поток, который пытается захватить блокировку, ждать, выполняя цикл (спин), в течение определённого времени, прежде чем уступить своё квантовое время. В сценариях, когда ожидание блокировки, как ожидается, будет коротким, SpinLock обеспечивает лучшую производительность, чем другие формы блокировки. Дополнительные сведения см. в разделе SpinLock.
System.Threading.SpinWait Небольшой, легкий тип, который будет вращаться в течение указанного времени и в конечном итоге помещает поток в состояние ожидания, если количество вращений превышено. Дополнительные сведения см. в разделе SpinWait.

Дополнительные сведения можно найти здесь

Классы отложенной инициализации

При отложенной инициализации память для объекта не выделяется, пока она не понадобится. Отложенная инициализация может повысить производительность путем равномерного распределения объектов в течение всего времени существования программы. Вы можете включить отложенную инициализацию для любого пользовательского типа, завернув тип Lazy<T>.

В следующей таблице перечислены типы отложенной инициализации.

Тип Описание
System.Lazy<T> Обеспечивает упрощенную, потокобезопасную отложенную инициализацию.
System.Threading.ThreadLocal<T> Предоставляет неявное инициализированное значение на основе каждого потока, при этом каждый поток лениво вызывает функцию инициализации.
System.Threading.LazyInitializer Предоставляет статические методы, которые устраняют необходимость в выделении отдельного экземпляра для ленивой инициализации. Вместо этого они используют ссылки для обеспечения инициализации целевых объектов по мере доступа.

Дополнительные сведения см. в ленивой инициализации.

Агрегированные исключения

Тип System.AggregateException можно использовать для записи нескольких исключений, которые создаются одновременно в отдельных потоках, и возвращать их в присоединенный поток в виде одного исключения. Типы System.Threading.Tasks.Task, System.Threading.Tasks.Parallel и PLINQ активно используют AggregateException для этой цели. Дополнительные сведения см. в разделе "Обработка исключений " и "Практическое руководство. Обработка исключений в запросе PLINQ".

См. также