Структуры данных для параллельного программирования
В .NET Framework версии 4 представлено несколько новых типов, полезных в параллельном программировании, включая набор классов параллельных коллекций, примитивы упрощенной синхронизации и типы неактивной инициализации. Эти типы можно использовать с любым кодом многопоточного приложения, включая библиотеку параллельных задач и PLINQ.
Классы параллельных коллекций
Классы коллекций в пространстве имен System.Collections.Concurrent предоставляют потокобезопасные операции добавления и удаления, которые по возможности избегают блокировок и используют блокировку мелких фрагментов данных там, где необходима блокировка. В отличие от коллекций, которые были введены в .NET Framework версий 1.0 и 2.0, класс параллельных коллекций не требует, чтобы пользовательский код принимал какие-либо блокировки при доступе к элементам. Классы параллельных коллекций могут значительно увеличить производительность по сравнению с типами, такими как System.Collections.ArrayList и System.Collections.Generic.List<T> (с реализованной пользователем блокировкой), в сценариях, где несколько потоков добавляют и удаляют элементы из коллекции.
В следующей таблице перечислены новые классы параллельных коллекций.
Тип |
Описание |
---|---|
Предоставляет возможности блокировки и ограничения для потокобезопасных коллекций, реализующих System.Collections.Concurrent.IProducerConsumerCollection<T>. Потоки-производители блокируются, если слоты отсутствуют или коллекция является полной. Потоки-потребители блокируются, если коллекция пуста. Этот тип также поддерживает неблокирующий доступ потребителей и производителей. Коллекцию BlockingCollection<T> можно использовать в качестве базового класса или резервного хранилища для предоставления блокировки и ограничения для любого класса коллекции, поддерживающего IEnumerable<T>. |
|
Потокобезопасная реализация наборов, предоставляющая масштабируемые операции добавления и получения. |
|
System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue> |
Тип параллельного и масштабируемого словаря. |
Параллельная и масштабируемая очередь FIFO. |
|
Параллельный и масштабируемый стек LIFO. |
Дополнительные сведения см. в разделе Потокобезопасные коллекции.
Примитивы синхронизации
Новые примитивы синхронизации в пространстве имен System.Threading обеспечивают детализацию параллелизма и повышенную производительность благодаря исключению ресурсоемких механизмов блокировки, которые используются в устаревшем многопоточном коде. Некоторые новые типы, например System.Threading.Barrier и System.Threading.CountdownEvent, не имеют аналогов в более ранних выпусках платформы .NET Framework.
В следующей таблице перечислены новые типы синхронизации.
Тип |
Описание |
---|---|
Включает несколько потоков для параллельной работы с алгоритмом, предоставляя точку, в которой каждая задача может сигнализировать о своем поступлении, а затем блокироваться до тех пор, пока не поступят некоторые или все задачи. Дополнительные сведения см. в разделе Барьер (.NET Framework). |
|
Упрощает сценарии разветвления и объединения, предоставляя простой механизм сближения. Дополнительные сведения см. в разделе CountdownEvent. |
|
Примитив синхронизации, аналогичный System.Threading.ManualResetEvent. ManualResetEventSlim является более простым типом, но может быть использован для взаимодействия внутри процесса. Дополнительные сведения см. в разделе Классы ManualResetEvent и ManualResetEventSlim. |
|
Примитив синхронизации, ограничивающий количество потоков, которые могут параллельно обращаться к ресурсу или пулу ресурсов. Дополнительные сведения см. в разделе Классы Semaphore и SemaphoreSlim. |
|
Примитив взаимно исключающей блокировки, вызывающий поток, который пытается получить блокировку для ожидания в цикле или spin для периода времени до возврата такта. В сценариях, в которых предполагается, что ожидание блокировки будет коротким, SpinLock предлагает более высокую производительность по сравнению с другими формами блокировки. Дополнительные сведения см. в разделе SpinLock. |
|
Небольшой более простой тип, который будет вращаться в течение определенного времени и со временем приведет к переходу потока в состояние ожидания, если будет превышено число прокруток. Дополнительные сведения см. в разделе SpinWait. |
Дополнительные сведения см. в следующих разделах.
Практическое руководство. SpinLock и низкоуровневая синхронизация
Практическое руководство. Синхронизация параллельных операций с барьером.
Классы неактивной инициализации
При неактивной инициализации память для объекта не выделяется, пока не понадобится. Неактивная инициализация может повысить производительность, равномерно распределения объекты во времени существования программы. Неактивную инициализацию любого пользовательского типа можно реализовать, создав программу-оболочку для типа Lazy<T>.
В следующей таблице перечислены типы неактивной инициализации.
Тип |
Описание |
---|---|
Предоставляет упрощенную, потокобезопасную неактивную инициализацию. |
|
Предоставляет неактивно инициализированное значение на основе отдельного потока, при этом каждый поток неактивно вызывает функцию инициализации. |
|
Предоставляет статические методы, устраняющие потребность в выделенном экземпляре неактивной инициализации. Вместо этого используются ссылки для обеспечения инициализации целевых объектов при доступе к ним. |
Дополнительные сведения см. в разделе Отложенная инициализация.
Агрегатные исключения
Тип System.AggregateException можно использовать для фиксации нескольких исключений, параллельно создаваемых в отдельных потоках, и возвращения их в присоединяемый поток в виде одного исключения. Типы System.Threading.Tasks.Task и System.Threading.Tasks.Parallel, а также PLINQ активно используют для этого исключение AggregateException. Дополнительные сведения см. в разделах Практическое руководство. Обработка исключений, создаваемых задачами и Практическое руководство. Обработка исключений в запросе PLINQ.