RingBuffer Size
affects performance, shoule be 1024 or larger.
Disruptor is 10x faster than BlockingCollection with multi producer (10 parallel producet), 2x faster than BlockingCollection with Single producer:
1 using System; 2 using System.Collections.Concurrent; 3 using System.Diagnostics; 4 using System.Threading; 5 using System.Threading.Tasks; 6 using Disruptor; 7 using Disruptor.Dsl; 8 using NUnit.Framework; 9 10 namespace DisruptorTest.Ds 11 { 12 public sealed class ValueEntry 13 { 14 internal int Id { get; set; } 15 } 16 17 class MyHandler : IEventHandler<ValueEntry> 18 { 19 public void OnEvent(ValueEntry data, long sequence, bool endOfBatch) 20 { 21 } 22 } 23 24 [TestFixture] 25 public class DisruptorPerformanceTest 26 { 27 private volatile bool collectionAddEnded; 28 29 private int producerCount = 10; 30 private int runCount = 1000000; 31 private int RingBufferAndCapacitySize = 1024; 32 33 [TestCase()] 34 public async Task TestBoth() 35 { 36 for (int i = 0; i < 1; i++) 37 { 38 foreach (var rs in new int[] {64, 512, 1024, 2048 /*,4096,4096*2*/}) 39 { 40 Console.WriteLine($"RingBufferAndCapacitySize:{rs}, producerCount:{producerCount}, runCount:{runCount} of {i}"); 41 RingBufferAndCapacitySize = rs; 42 await DisruptorTest(); 43 await BlockingCollectionTest(); 44 } 45 } 46 } 47 48 [TestCase()] 49 public async Task BlockingCollectionTest() 50 { 51 var sw = new Stopwatch(); 52 BlockingCollection<ValueEntry> dataItems = new BlockingCollection<ValueEntry>(RingBufferAndCapacitySize); 53 54 sw.Start(); 55 56 collectionAddEnded = false; 57 58 // A simple blocking consumer with no cancellation. 59 var task = Task.Factory.StartNew(() => 60 { 61 while (!collectionAddEnded && !dataItems.IsCompleted) 62 { 63 //if (!dataItems.IsCompleted && dataItems.TryTake(out var ve)) 64 if (dataItems.TryTake(out var ve)) 65 { 66 } 67 } 68 }, TaskCreationOptions.LongRunning); 69 70 71 var tasks = new Task[producerCount]; 72 for (int t = 0; t < producerCount; t++) 73 { 74 tasks[t] = Task.Run(() => 75 { 76 for (int i = 0; i < runCount; i++) 77 { 78 ValueEntry entry = new ValueEntry(); 79 entry.Id = i; 80 dataItems.Add(entry); 81 } 82 }); 83 } 84 85 await Task.WhenAll(tasks); 86 87 collectionAddEnded = true; 88 await task; 89 90 sw.Stop(); 91 92 Console.WriteLine($"BlockingCollectionTest Time:{sw.ElapsedMilliseconds/1000d}"); 93 } 94 95 96 [TestCase()] 97 public async Task DisruptorTest() 98 { 99 var disruptor = 100 new Disruptor.Dsl.Disruptor<ValueEntry>(() => new ValueEntry(), RingBufferAndCapacitySize, TaskScheduler.Default, 101 producerCount > 1 ? ProducerType.Multi : ProducerType.Single, new BlockingWaitStrategy()); 102 disruptor.HandleEventsWith(new MyHandler()); 103 104 var _ringBuffer = disruptor.Start(); 105 106 Stopwatch sw = Stopwatch.StartNew(); 107 108 sw.Start(); 109 110 111 var tasks = new Task[producerCount]; 112 for (int t = 0; t < producerCount; t++) 113 { 114 tasks[t] = Task.Run(() => 115 { 116 for (int i = 0; i < runCount; i++) 117 { 118 long sequenceNo = _ringBuffer.Next(); 119 _ringBuffer[sequenceNo].Id = 0; 120 _ringBuffer.Publish(sequenceNo); 121 } 122 }); 123 } 124 125 126 await Task.WhenAll(tasks); 127 128 129 disruptor.Shutdown(); 130 131 sw.Stop(); 132 Console.WriteLine($"DisruptorTest Time:{sw.ElapsedMilliseconds/1000d}s"); 133 } 134 } 135 }
BlockingCollectionTest with a shared ValueEntry instance (no new ValueEntry() in for loop)
-
RingBufferAndCapacitySize:64, producerCount:10, runCount:1000000 of 0
DisruptorTest Time:16.962s
BlockingCollectionTest Time:18.399
-
RingBufferAndCapacitySize:512, producerCount:10, runCount:1000000 of 0 DisruptorTest Time:6.101s
BlockingCollectionTest Time:19.526
-
RingBufferAndCapacitySize:1024, producerCount:10, runCount:1000000 of 0
DisruptorTest Time:2.928s
BlockingCollectionTest Time:20.25
-
RingBufferAndCapacitySize:2048, producerCount:10, runCount:1000000 of 0
DisruptorTest Time:2.448s
BlockingCollectionTest Time:20.649
BlockingCollectionTest create a new ValueEntry() in for loop
-
RingBufferAndCapacitySize:64, producerCount:10, runCount:1000000 of 0
DisruptorTest Time:27.374s
BlockingCollectionTest Time:21.955
-
RingBufferAndCapacitySize:512, producerCount:10, runCount:1000000 of 0
DisruptorTest Time:5.011s
BlockingCollectionTest Time:20.127
-
RingBufferAndCapacitySize:1024, producerCount:10, runCount:1000000 of 0
DisruptorTest Time:2.877s
BlockingCollectionTest Time:22.656
-
RingBufferAndCapacitySize:2048, producerCount:10, runCount:1000000 of 0
DisruptorTest Time:2.384s
BlockingCollectionTest Time:23.567