Disruptor.NET 性能测试:10倍于 BlockingCollection

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

猜你喜欢

转载自www.cnblogs.com/darklx/p/11755686.html