Contention/lock is bad. Array or LinkedList based queue is slow because of data contention inherent within the queue data structure (Both the consumer and producer need to modify the state of the queue).
A disruptor is a circular buffer that does not track anything but the next available slot for write and the most recently available slot for read/consume. The progress of publisher and consumers are tracked separately by their respective sequences.
Consumers just read from the circular buffer, only the publisher writes to the circular buffer, aka. the single-writer principle.
The circular buffer is a preallocated array, alleviating pressure from GC.
Consumers can have dependencies on each other, composing a dependency graph that represents the data processing work flow.
Each entity (Consumer/Producer) has a Sequence that tracks its current progress. They can have dependency on each other via SequenceBarrier, which is used to track the set of dependent sequences.
Each of the consumers and the publisher should ideally run in its own dedicated thread (hardware thread), thus does not get context switched and have their cache invalidated.
Under the hood, it is implemented with the use of Java Memory Consistency Model and memory barrier (volatile).
It leverages memory padding to avoid false sharing, two pieces of independent of data accessed by two different threads are placed on a single cache line, causing cache invalidation on the other when one is modified.
For introduction, watch https://www.infoq.com/presentations/Concurrent-Programming-Using-The-Disruptor.
For detailed treatment of memory consistent model, read A Primer on Memory Consistency and Cache Coherence by Daniel J. Sorin, Mark D. Hill, and David A. Wood
No comments:
Post a Comment