What is better and why to use List as thread safe: BlockingCollection or ReaderWriterLockSlim or lock?
-
12-06-2021 - |
문제
I have System.Collections.Generic.List _myList
and many threads can read from it or add items to it simultaneously. From what I've read I should using 'BlockingCollection' so this will work. I also read about ReaderWriterLockSlim
and lock
, but I don't figure out how to use them instead of BlockingCollection
, so my question is can I do the same with:
- ReaderWriterLockSlim
- lock
instead of using 'BlockingCollection'. If YES, can you please provide simple example and what pros and cons of using BlockingCollection
, ReaderWriterLockSlim
, lock
?
UPDATED readers will be much more than writers!
해결책
ReaderWriterLockSlim
:
- is optimized for use cases, when reads from resourse occur more frequently, than writes;
- can work with any type of resources (not only collections), because it's just a hybrid synchronization construct.
lock
:
- is a general purpose, rather simple, hybrid synchronization construct without any optimizations; thus, can make performance worse;
- is a C# wrapper around
Monitor
class; - can work with any type of resources;
BlockingCollection
:
- is a specific type of collection (concrete type of resource), that oriented to solve 'producer-consumer' tasks;
- supports timeouts and cancellation mechanism (via cancellation tokens), which makes easier integration into code, which uses TPL.
I think, your choice is BlockingCollection
(if you really have many readers and writers).
다른 팁
If you are mutating the list frequently, then ReaderWriterLockSlim
probably isn't going to help you, as that only allows single write access, and lock
is less overhead. Personally, I would just lock
(on some lock object) for the duration of each access.
The problem with a BlockingCollection
is that it only guarantees that individual operations are atomic - however, quite often we need to perform multiple operations as a unit (more than just TryAdd
, etc). So in order to avoid crazy, a lock
is simpler.
The other advantage is that the usage of lock
is very simple:
lock(syncLock) {
// do stuff with the list
}
(it also has inbuilt signalling via Monitor.Wait
and Monitor.Pulse*
, which is nice)