-
Notifications
You must be signed in to change notification settings - Fork 227
ValueDisruptor
One of the reasons the Disruptor is fast is that the events benefit from good data prefetching. This prefetching is possible because the events are processed sequentially and because they are layout mostly sequentially and packed in memory.
The ValueDisruptor is built on a value type based ring buffer, the ValueRingBuffer<T>
. The goal of the ValueDisruptor is to provide a perfectly packed ring buffer while removing a level of indirection. Those two characteristics allow the ValueDisruptor to have a better throughput and a better latency than the default Disruptor.
Yet, choosing a struct for events has one downside: using reference types for nested members becomes inefficient. Because sub-objects will be allocated outside the event array, they will not be stored contiguously to the struct data. Therefore, you should not use ValueDisruptor if you need sub-object in your events. Of course, you can still use other value types for nested members.
The ValueDisruptor API is very similar to the Disruptor
-
Disruptor<T>
=>ValueDisruptor<T>
-
RingBuffer<T>
=>ValueRingBuffer<T>
-
IEventHandler<T>
=>IValueEventHandler<T>
The most notable change is that the value event instances are always passed or returned by-ref to avoid slow copies and to support mutability.
Here is a simple ValueDisruptor usage:
public struct ValueEvent
{
public int Id;
public double Value;
}
public class ValueEventHandler : IValueEventHandler<ValueEvent>
{
public void OnEvent(ref ValueEvent data, long sequence, bool endOfBatch)
{
Console.WriteLine($"{data.Id}: {data.Value}");
}
}
public static void SetupDisruptor()
{
_disruptor = new ValueDisruptor<ValueEvent>(() => new ValueEvent(), ringBufferSize: 1024);
_disruptor.HandleEventsWith(new ValueEventHandler());
_disruptor.Start();
}
public static void PublishEvent(int id, double value)
{
using (var scope = _disruptor.PublishEvent())
{
ref var data = ref scope.Event();
data.Id = id;
data.Value = value;
}
}
Note that another value type based Disruptor is available: UnmanagedDisruptor<T>
. This Disruptor allows one to build a Disruptor using a pre-allocated, unmanaged memory block.