День двести пятьдесят седьмой. #ЗаметкиНаПолях
Использование потокобезопасных коллекций. Начало
Потокобезопасные элементы работают правильно, когда используются из нескольких потоков (задач) одновременно. Стандартные коллекции .NET (
Предоставляет потокобезопасную коллекцию, обслуживаемую по принципу "первым поступил — первым обслужен" (FIFO). Метод
Синхронизация обеспечивается внутри
Третий метод,
ConcurrentStack
Класс
Можно перечислить элементы очереди или стека (программа может использовать конструкцию
Свойство
ConcurrentBag
Представляет потокобезопасный контейнер неупорядоченной коллекции объектов. Метод
Контейнеры полезны для хранения элементов, когда порядок не имеет значения, и в отличие от наборов, контейнеры поддерживают дублирование элементов.
Источники:
- Rob Miles “Exam Ref 70-483 Programming in C#”. 2nd ed - Pearson Education, Inc., 2019. Глава 1.
- https://docs.microsoft.com/en-us/dotnet/api/system.collections.concurrent?view=netframework-4.8
Использование потокобезопасных коллекций. Начало
Потокобезопасные элементы работают правильно, когда используются из нескольких потоков (задач) одновременно. Стандартные коллекции .NET (
List
, Queue
или Dictionary
) не являются потокобезопасными. Библиотеки .NET предоставляют классы потокобезопасных коллекций, которые можно использовать при создании многозадачных приложений: BlockingCollection<Т>
, ConcurrentQueue<Т>
, ConcurrentStack<Т>
, ConcurrentBag<Т>
, ConcurrentDictionary<TKey, TValue>
ConcurrentQueueПредоставляет потокобезопасную коллекцию, обслуживаемую по принципу "первым поступил — первым обслужен" (FIFO). Метод
Enqueue
добавляет элементы в очередь, а метод TryDequeue
удаляет их. Обратите внимание, что, хотя метод Enqueue
гарантированно сработает (очереди могут иметь бесконечную длину), метод TryDequeue
вернет false
в случае сбоя при извлечении из очереди. Синхронизация обеспечивается внутри
ConcurrentQueue<T>
. Если два потока вызывают TryDequeue
в один и тот же момент, ни одна из операций не блокируется. При обнаружении конфликта между двумя потоками, один поток должен попытаться снова получить следующий элемент.TryDequeue
пытается удалить элемент из очереди. Это происходит атомарно по отношению к другим операциям в очереди. Если очередь была заполнена элементами a
, b
и c
, и два потока одновременно пытаются удалить из очереди элемент, один поток удалит из очереди a, а другой поток удалит из очереди b
. Оба вызова TryDequeue
вернут true
, потому что они оба смогли удалить элемент из очереди. Если каждый поток попытается извлечь ещё по одному элементу, один из потоков удалит из очереди c
и вернёт true
, тогда как другой поток найдёт очередь пустой и вернет false
.Третий метод,
TryPeek
, позволяет программе проверить элемент в начале очереди, не извлекая его. Заметьте, что даже если метод TryPeek
возвратит элемент, последующий вызов метода TryDequeue
в том же потоке, для извлечения этого элемента из очереди, может завершиться неудачей, если элемент будет извлечён в другом потоке.ConcurrentStack
Класс
ConcurrentStack
обеспечивает поддержку потокобезопасных стеков Элементы обслуживаются по принципу «первым пришёл – последним обслужен» (LIFO). Метод Push
добавляет элементы в стек, а метод TryPop
извлекает их. Существуют также методы PushRange
и TryPopRange
, которые можно использовать для добавления или извлечения нескольких элементов.Можно перечислить элементы очереди или стека (программа может использовать конструкцию
foreach
для работы с каждым элементом в очереди). В начале перечисления параллельная очередь предоставит моментальный снимок содержимого.Свойство
Count
возвращает количество элементов в коллекции, а свойство IsEmpty
сообщает, является ли коллекция пустой (его предпочтительнее использовать, вместо сравнения Count
с 0
). Но вследствие многопоточного использования, значения этих свойств могут сразу же терять актуальность из-за действий в других потоках.ConcurrentBag
Представляет потокобезопасный контейнер неупорядоченной коллекции объектов. Метод
Add
помещают элементы в коллекцию, а метод TryTake
извлекает их. Существует также метод TryPeek
, но он менее полезен в ConcurrentBag
, поскольку возможно, что последующий метод TryTake
вернет другой элемент.Контейнеры полезны для хранения элементов, когда порядок не имеет значения, и в отличие от наборов, контейнеры поддерживают дублирование элементов.
ConcurrentBag<T>
оптимизирован для сценариев, в которых один и тот же поток будет как производить, так и потреблять данные, хранящиеся в контейнере. ConcurrentBag<T>
может принимать null
в качестве допустимого значения для ссылочных типов. Источники:
- Rob Miles “Exam Ref 70-483 Programming in C#”. 2nd ed - Pearson Education, Inc., 2019. Глава 1.
- https://docs.microsoft.com/en-us/dotnet/api/system.collections.concurrent?view=netframework-4.8