Git Product home page Git Product logo

disruptor-net's Introduction

Disruptor-net

Build NuGet

Overview

The Disruptor is a high performance inter-thread message passing framework. This project is the .NET port of LMAX Disruptor.

The Disruptor can be succinctly defined as a circular queue with a configurable sequence of consumers. The key features are:

  • Zero memory allocation after initial setup (the events are pre-allocated).
  • Push-based consumers.
  • Optionally lock-free.
  • Configurable wait strategies.

Release notes

Version 5.0.0 has been released and is available on NuGet.

Supported runtimes

  • .NET 5.0+
  • .NET Standard 2.1

Basic usage

First, you need to define your event (message) type:

public class SampleEvent
{
    public int Id { get; set; }
    public double Value { get; set; }
}

You also need to create a consumer:

public class SampleEventHandler : IEventHandler<SampleEvent>
{
    public void OnEvent(SampleEvent data, long sequence, bool endOfBatch)
    {
        Console.WriteLine($"Event: {data.Id} => {data.Value}");
    }
}

Then you can setup the Disruptor:

var disruptor = new Disruptor<SampleEvent>(() => new SampleEvent(), ringBufferSize: 1024);

disruptor.HandleEventsWith(new SampleEventHandler());

disruptor.Start();

Finally, you can publish events:

using (var scope = disruptor.PublishEvent())
{
    var data = scope.Event();
    data.Id = 42;
    data.Value = 1.1;
}

Go to the wiki for a more detailed introduction.

License

Copyright Olivier Deheurles

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this project except in compliance with the License.

You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

disruptor-net's People

Contributors

ablanchet avatar bblackburn avatar buybackoff avatar damageboy avatar ltrzesniewski avatar mendelmonteiro avatar minhhungit avatar ocoanet avatar saiguefault avatar tahazayed avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

disruptor-net's Issues

The latest build as of 2011-12-28 runs extremely slowly within Visual Studio

Hi,

Downloaded the program, if I compile it with "build.bat" and run "runPerfTests.bat", it works fine (30 million per second for first test).

However, it I compile it with Visual Studio 2010, and run it within Visual Studio with the same commandline ("0 0 3"), it runs excruciatingly slow: 16,000 per second in Debug mode, and 22,000 per second in Release mode. I had to change the default of 100 million tests to 1 million to make it run in less than 90 minutes.

I have a high end Dell T7500 server, with HyperThreading turned off (turning it on makes no difference).

The lastest build as of 2011-12-28 throws exceptions during build process

Hi,

I downloaded the code, compiled it using "build.bat", and it seemed to throw an exception during the build process:

Test:
T:\Phi v2\Trading Account Simulator\Trading Account Simulator\Third Party Libraries\DisruptorNet\odeheurles-Disruptor-net-3e79c
it\nunit-console.exe /nologo "T:\Phi v2\Trading Account Simulator\Trading Account Simulator\Third Party Libraries\DisruptorNet
-Disruptor-net-3e79ce9\Target\Bin\Disruptor.Tests.dll" /xml="T:\Phi v2\Trading Account Simulator\Trading Account Simulator\Thi
ibraries\DisruptorNet\odeheurles-Disruptor-net-3e79ce9\Target\Report\Unit\UnitTests.xml"
ProcessModel: Default DomainUsage: Single
Execution Runtime: net-4.0.30319.239
.............................Exception processing sequence 0 for event Value: 0, TestString: : System.Exception: Exception of t
m.Exception' was thrown.
.Exception processing sequence 0 for event Value: 0, TestString: : System.Exception: Exception of type 'System.Exception' was t

Strong Naming the Disruptor Assembly?

Hi,

We want to reference Disruptor from strong-named assemblies. This requires Disruptor to have a strong name, too. Up to now we create a strong-named version our-self, using something like this

ildasm Disruptor.dll /out:Disruptor.il
ilasm Disruptor.il /dll /key=path\to\SomeKey.snk

which is cumbersome and needs to be redone on every new version.

Do you mind signing the official Disruptor dlls on nuget.org right away, as part of your build?

Further reading: https://docs.microsoft.com/en-us/dotnet/standard/assembly/strong-named

Is it safe to use Disruptor with System.IO.Pipelines without extra allocations?

I have a TCP server application with binary protocol packets. The server uses System.IO.Pipeline to receive messages from the socket, frame them (length prefix) and later decode them in objects. I am looking to improve the performance by offloading the decoding of the message bytes with disruptor and later process the message. Is it safe to publish ReadOnlySequence resulted from message framing into Disruptor? I am looking for a way to avoid extra allocations (e.g. do not copy or transfer the sequence into a new byte buffer every time)

The code looks similar to this:

          var reader = socketConnection.Input;
            try
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    var readResult = await reader.ReadAsync(cancellationToken).ConfigureAwait(false);
                    var buffer = readResult.Buffer;
                    if (readResult.IsCanceled)
                        break;
                    
                    if (buffer.IsEmpty && readResult.IsCompleted) 
                        break;

                    var consumed = buffer.Start;
                    var examined = buffer.End;

                    if (FixedSizePipeProtocolFramer.TryParseLengthPrefixedPacket(in buffer, packetMaxSize, ref consumed, ref examined, out ReadOnlySequence<byte> payload)) {
                        //do something with payload like publishing into disruptor's ring buffer. Is it safe?
                    }
                    if (readResult.IsCompleted)
                        break;

                    reader.AdvanceTo(consumed, examined);
                }
            }
[...]

EventPoller for ValueRingBuffer

Hi there,

I have something already implemented with RingBuffer together with the EventPoller. I'm trying to migrate events from classes to structs but stuck as there isn't an EventPoller for ValueRingBuffer.

I find the EventPoller useful because I have a single thread handling events from multiple RingBuffers.

What is the best way to do this if EventPoller isn't available for ValueRingBuffer? Happy to help implementing it if this is the way to go.

Thanks for the great work!

version 3.4.0 cause 'Invalid IL code in Disruptor.Util' on mono 5.18.0

Mono JIT compiler version 5.18.0.268
Debian 9
I run a mono xxx.exe command, and throw exception like :

System.TypeInitializationException: The type initializer for 'Disruptor.Util' threw an exception. ---> System.InvalidProgramException: Invalid IL code in Disruptor.Util:ElemOffset (object[]): IL_0008: sub

  at Disruptor.Util..cctor () [0x00000] in <a2688bbefc9a4db192615b1757478ef2>:0
   --- End of inner exception stack trace ---
  at Disruptor.MultiProducerSequencer..ctor (System.Int32 bufferSize, Disruptor.IWaitStrategy waitStrategy) [0x0003b] in <a2688bbefc9a4db192615b1757478ef2>:0

WorkerPool support in DSL.

Hi guys, it's not an issue, I just wanted to make you aware that I've ported WorkerPool support from 3.* in my fork, so when you'll get around to the third version, you could save some time with my code.

Thank you for your project, I really appreciate it!

Too many producers with MultiThreadedLowContentionClaimStrategy caused 100% cpu

Ran into an issue when I used a small ring buffer (2048) and then had more producers than I had CPU cores. This put the machine in a state where "SerialisePublishing" would go into a spin wait state waiting for a sequence to increment. Sadly, enough of these get into this state and the machine just caps at 100% and everything goes to a 'crawl' from 1+ million per second to sub 1k per second (sometimes even in the 10's per second). I've created a small patch on the SerialisePublishing function to Thread.Yield after a certain number of iterations (10-100 iterations seems to work well) to allow another thread on that cpu core which may increment the necessary sequence to allow the spin wait to complete successfully. It spends so much time checking for the increment that it doesn't give time for a thread to actually do the increment (or at least seems so from my testing)

On my 8 core machine, before the patch I could go 1.3 + million with 8 producers, 9 producers would put me at 1-2k and 100% cpu usage.

After patch I can now go 1.1+ million with 16 producers with no problem (the more I add the slower it goes, but this is expected)

Lower number of producers seem to keep the same performance characteristics as before the patch.

add Task and async support for 'OnEvent' and 'Publish'

Disruptor is a great project with advanced technology. Thank you for bringing Disruptor to the .NET world.

The async and await signal-based wake-up mechanisms can significantly increase throughput.

I think if bring the async to the disruptor, it can avoid the CPU overhead of Blocking Strategy and Yield Strategy while waiting for new events to arrive, could you tell me is that true?

Exception free TryNext

Exceptions are expensive, and should be avoided if possible.

Would it be possible to add exception free overloads

        bool TryNext(int n, out long next);
        bool TryNext(out long next);

That follows normal "TryGet" conventions

Buffer getting full

I'm trying to use IBatchEventHandler.
I"ve implemented the OnBatch(EventBatch messages, long sequence)
It basicaly executes a foreach loop:

foreach(var message in messages.AsEnumerable())
{
// do something with the message
}

But it seems that the buffer never gets cleared and after a while, the publisher blocks waiting for the consumer and it seems like the consumer is not consuming, although there is the foreach that is consuming data. Am I missing something to remove the elements from the ringBuffer?

EventHandlerGroup<T>.And(EventHandlerGroup<T> eventHandlerGroup) usage

Can you explain how I use the And() method on the EventHandlerGroup class? The only method I can see to create an EventHandlerGroup object without already having one is on the disruptor class. I am trying to use it to be able to have two separate WorkerPools in the same consumer group.

Would the following achieve it?

var someHandlers = disruptor.HandleEventsWithWorkerPool(SomeWorkHandlers);
disruptor.HandleEventsWithWorkerPool(filterMessageWorkHandlers).And(someHandlers);

Proposal: Remove exception based APIs

The codebase contains a few exception based APIs:

  • InsufficientCapacityException, thrown in RingBuffer.TryNext() and RingBuffer.TryNext(int).
  • TimeoutException, thrown in timeout-based wait strategies.
  • AlertException, thrown when stopping the event processors.

I think that, at least for the first two cases, the exception usage is against Framework design guidelines in addition to being very bad regarding performance.

In my view InsufficientCapacityException can be removed along with the RingBuffer.TryNext() and RingBuffer.TryNext(int) methods. There are now overloads for these methods that follow the .NET convention (see #33) and there is no point in keeping the other ones.

TimeoutException could also be simply removed but it would be a feature loss for projets using timeout-based wait strategies and ITimeoutHandler. An other option is to change the IWaitStrategy to allow the wait strategies to returns timeouts. For example:

public interface IWaitStrategy
{
    WaitResult WaitFor(ref long sequence, Sequence cursor, ISequence dependentSequence, ISequenceBarrier barrier);
    // ....
}

public enum WaitResult
{
    Success,
    Timeout,
}

I am not fond of AlertException, but this exception is not really an issue because it is only used to stop the event processors. However, a change in the IWaitStrategy could also be used to get rid of the exception, for example:

public enum WaitResult
{
    Success,
    Timeout,
    Canceled,
}

What do you think?

Does Disruptor support asynchronous EventHandler?

I got a use case that need to call asynchronous functions in EventHandler, but I am not sure if I could have async OnEvent function or not.

I skimmed the code, look like after calling OnEvent, the avaiableSequence is advanced. But it OnEvent is a asyn function, the task may not complete yet, which may still read the data in Event.

So I suspect that async OnEvent is not acceptable and want to confirm if this is the case.

If it is not okay to have async OnEvent, what would be the suggested way to call asynchronous function (Which might be IO bounded) ?

Replace interface-based publish methods by delegate-based methods

With version 3.0 of the Disruptor, a lambda-style API was added to the Java version. This API was quite naively copied in .NET, which is unfortunate because Java lambdas are interface-based while .NET lambdas are delegate-based. Thus, the lambda-style API is useless in .NET.

Proposal:

  • Make interface-based publish methods obsolete onRingBuffer, Disruptor and IEventSink.
[Obsolete("Use delegate-based PublishEvent instead")]
public void PublishEvent<A>(IEventTranslatorOneArg<T, A> translator, A arg0)
  • Make all event translator interfaces obsolete.
  • Add delegate-based publish methods.
public delegate void EventTranslator<TEvent, TArg0>(TEvent @event, long sequence, TArg0 arg0);
// ...
public void PublishEvent<TArg0>(EventTranslator<T, TArg0> translator, TArg0 arg0)

High CPU usage in MultiProducerSequencer.NextInternal(int)

In the production environment, I found 100% CPU usage, and then I DUMP 4 time points, found that thread 29 occupied abnormal time, and the MultiProducerSequencer.NextInternal function is seen in the stack.
In addition, in the AggressiveSpinWait.SpinOne(), I wonder why Thread.Sleep(0) is used instead of Thread.Sleep(1).
Thanks.

The following is the stack of thread 29 at 4 time points.

0:000> ~29e!clrstack -a
OS Thread Id: 0x32e0 (29)
        Child SP               IP Call Site
000000cb4dd3f3d8 00007fff8c956964 [InlinedCallFrame: 000000cb4dd3f3d8] System.Threading.Thread.YieldInternal()
000000cb4dd3f3d8 00007fff7b4466c8 [InlinedCallFrame: 000000cb4dd3f3d8] System.Threading.Thread.YieldInternal()
000000cb4dd3f3b0 00007fff7b4466c8 DomainNeutralILStubClass.IL_STUB_PInvoke()

000000cb4dd3f460 00007fff24d55f6b Disruptor.AggressiveSpinWait.SpinOnce()
    PARAMETERS:
        this (<CLR reg>) = 0x000000cb4dd3f4b8

000000cb4dd3f490 00007fff22bff3af Disruptor.MultiProducerSequencer.NextInternal(Int32)
    PARAMETERS:
        this (<CLR reg>) = 0x000002cbac10fcf8
        n (<CLR reg>) = 0x0000000000000001
    LOCALS:
        <no data>
        <no data>
        <no data>
        <no data>
        <no data>
        <no data>
0:000> ~29e!clrstack -a
OS Thread Id: 0x32e0 (29)
        Child SP               IP Call Site
000000cb4dd3f440 00007fff233ac68b Disruptor.Util.GetMinimumSequence(Disruptor.ISequence[], Int64)
    PARAMETERS:
        sequences (<CLR reg>) = 0x000002cbac358790
        minimum (<CLR reg>) = 0x000000000518aae7
    LOCALS:
        <CLR reg> = 0x0000000000000003
        <no data>

000000cb4dd3f490 00007fff22bff3a0 Disruptor.MultiProducerSequencer.NextInternal(Int32)
    PARAMETERS:
        this (<CLR reg>) = 0x000002cbac10fcf8
        n (<CLR reg>) = 0x0000000000000001
    LOCALS:
        <no data>
        <no data>
        <no data>
        <CLR reg> = 0x000000000518aae8
        <no data>
        <no data>
0:000> ~29e!clrstack -a
OS Thread Id: 0x32e0 (29)
        Child SP               IP Call Site
000000cb4dd3f338 00007fff8c956724 [HelperMethodFrame: 000000cb4dd3f338] System.Threading.Thread.SleepInternal(Int32)
000000cb4dd3f430 00007fff7b3d6e8a System.Threading.Thread.Sleep(Int32)
    PARAMETERS:
        millisecondsTimeout = <no data>

000000cb4dd3f460 00007fff24d55f64 Disruptor.AggressiveSpinWait.SpinOnce()
    PARAMETERS:
        this (<CLR reg>) = 0x000000cb4dd3f4b8

000000cb4dd3f490 00007fff22bff3af Disruptor.MultiProducerSequencer.NextInternal(Int32)
    PARAMETERS:
        this (<CLR reg>) = 0x000002cbac10fcf8
        n (<CLR reg>) = 0x0000000000000001
    LOCALS:
        <no data>
        <no data>
        <no data>
        <no data>
        <no data>
        <no data>
0:000> ~29e!clrstack -a
OS Thread Id: 0x32e0 (29)
        Child SP               IP Call Site
000000cb4dd3f3d8 00007fff8c956964 [InlinedCallFrame: 000000cb4dd3f3d8] System.Threading.Thread.YieldInternal()
000000cb4dd3f3d8 00007fff7b4466c8 [InlinedCallFrame: 000000cb4dd3f3d8] System.Threading.Thread.YieldInternal()
000000cb4dd3f3b0 00007fff7b4466c8 DomainNeutralILStubClass.IL_STUB_PInvoke()

000000cb4dd3f460 00007fff24d55f6b Disruptor.AggressiveSpinWait.SpinOnce()
    PARAMETERS:
        this (<CLR reg>) = 0x000000cb4dd3f4b8

000000cb4dd3f490 00007fff22bff3af Disruptor.MultiProducerSequencer.NextInternal(Int32)
    PARAMETERS:
        this (<CLR reg>) = 0x000002cbac10fcf8
        n (<CLR reg>) = 0x0000000000000001
    LOCALS:
        <no data>
        <no data>
        <no data>
        <no data>
        <no data>
        <no data>

Please update the project so that it runs straight out of the box

The following changes may make the project run straight out of the box, when compiled with Visual Studio:

  1. Make "Disruptor.PerfTests" the default project (the default is currently a library).
  2. Change "Disruptor.PerfTests" and "Command Line Arguments" to "0 0 1".
  3. Change the help if you don't give any command line parameters, it responds with the correct help, not "1 1" but "0 0 1".

And - the Disruptor pattern is awesome - thanks for the amazing work!

Is this supposed to work on *nix mono/core?

I get the exception on OSX targeting net461 (using mono 5.10) and/or netcoreapp2.0 (using 2.1.400 SDK):

System.TypeInitializationException: The type initializer for 'Disruptor.Util' threw an exception. ---> System.InvalidProgramException: Invalid IL code in Disruptor.Util:ElemOffset (object[]): IL_000d: sub

Any ideas?

Q: Send message to self

I'd like my consumer to send a message to itself now and then.
I just found that it's not safe to do so - if my buffer is dominated by messages to self the buffer stops processing - the capacity shrinks at every publish to self. There was a mention on stackoverflow of "custom event handler" that would make it possible to mark the message as processed, but I don't see how it can be done - not in the Java version, nor in .NET.
I tried introducing another disruptor in between, so that I don't publish directly into my own buffer, but that doesn't seem to help. Looking for ideas.

Task-based handlers

Some Disruptor-net users would like to use task-based API in their event handlers. The goal of this issue is to discuss whether supporting task-based handlers in the Disruptor is a good idea, and what the design of the API could be.

Async issues

The Disruptor has a "no-allocation" policy that make it quite hard to support async handlers. However, the goal of the "no-allocation" policy is to allow user applications to run in a "no-allocation" mode. If an application does not need the "no-allocation" mode, then it might be ok to allocate in the Disruptor. Of course, this behavior should be documented in the related types.

In addition, the idea of async handlers can be quite strange because:

  • Events are processed in order, so handler H1 should not start processing event E2 until E1 is processed, and handler H2 should not start processing event E1 before E1 is processed on H1.
  • Handlers use dedicated threads, so awaiting a task is not going to save any resource, and waiting is a perfectly fine approach.

Yet, I can understand that it feels better to write idiomatic async / await code than to wait, especially because waiting is an anti-pattern in other frameworks.

Async API

Here is a possible API for async handlers:

public interface IAsyncBatchEventHandler<T> where T : class
{
    ValueTask OnBatch(List<T> data, long sequence);
}

I see multiple options:

  • (A) The next event handler is allowed to start processing the current event before the current event task is completed.
  • (B) The event handler is allowed to start processing the next event before the current event task is completed.
  • (C) The continuations run in the event handler thread (i.e.: there is a custom synchronization context).

In a full "sequential" mode (A and B disabled, C enabled), the behavior would be identical to waiting for tasks in the event handler, but the code would be slightly cleaner and slower (because of the overhead of the task machinery).

In a full "async" mode (A and B enabled, C disabled), the behavior would be identical to fire-and-forgetting the tasks. I do not see any value in this mode, except for automatically sending the errors to an IExceptionHandler. This mode would be dangerous because it would hide queueing and prevent backpressure.

Other modes:

  1. Only waiting before processing events in the next handler (B enabled, A disabled). It can already be simply implemented by saving the Task inside the event and to wait for the task in the next handler.
  2. Only waiting before processing the next event in the current handler (A enabled, B disabled). It can already be simply implemented by saving the Task inside the handler and to wait for the task before processing the next event.

Right now, I do not see a lot of value in those options. I almost feel like a good documentation with all the implementation options would be more interesting than the API.

Please respond to this issue if you are interested in async handlers or if you think that I missed an option or an argument.

Single and MultiProducerSequencer confusion

I'm trying to understand how ProcessingSequenceBarrier barrier works together with MultiProducerSequencer and cannot figure something out.

Sequencer has _cursor field with is used differently in Single and MultiProducerSequencer. In SingleProducerSequencer _cursor points to last published item while in MultiProducerSequencer _cursor points to last claimed item.

When ProcessingSequenceBarrier created it receives _cursor field as cursorSequence parameter and then pass it to wait strategy. I see how this is correct with SingleProducerSequencer but I cannot understand why this works with MultiProducerSequencer.

I wonder if there is a potential for following scenario:

  1. MultiProducerSequencer.Next called and _cursor updated to say 10.
  2. Then ProcessingSequenceBarrier.WaitFor 8 called.
  3. WaitFor returns 10 but this sequence could be not yet published by producer.

Thanks

PerfTests doesn't compile when Nuget Disruptor is referenced

When you reference the Nuget "Disruptor-net" (containing atomic, Disruptor, Disruptor.Scheduler), directly from the Disruptor.PerfTests project, it doesn't compile anymore.

The compilation error happens in class ValueAdditionEventHandler has a private field of type "System.Threading.Volatile.PaddedLong".
Oddly enough, this is a type in assembly "System.Threading.Tasks.Dataflow" which is referenced correctly and remains untouched when adding the "Disruptor-net" Nuget.

Main question: in what way is the source in GitHub different from the sources used to build the Nuget package?

Long-running EventHandler causes high CPU consumption

This is probably outside of the expected use of Disruptor, but I'm wondering if there's a way I could solve this - blocking an event handler for a few minutes results in BlockingWaitStrategy waisting a lot of cycles. The handler on its own uses no more than 2% of one core, but running in the disruptor - 100% of a core.

I've tried other strategies, including a phased strategy with the fallback to seconds-long sleep and it doesn't help.

strange behavior with multiple eventhandlers

we use disruptor-net in an application with a number of ringbuffers. We also use an implementation of journalers much like the journaler odeheurles implemented.

Lately, we've had instances where we see an eventhandler run past the ringbuffer's cursor. This only happens on ringbuffers where we have a journaler.

the journaler is set with the disruptor's handlewith(IEventHandler[]) method, and then we use Then(IEventHandler[]) on the HandleGroup result. I think that is the correct way to do it if the journaler always has to process a sequence before the actual business logic gets to process the sequence.

I don't think the business logic event handler (which is the last to process a sequence) is the problem, that one just looks at the journaler to know which sequence can be processed. It's the journaler that runs past the cursor and takes the following eventhandler with it.

We've seen 4 cases of this, some disruptors had multiple writers, some a single writer, all had 2 eventhandlers (journaler+business logic).

Any idea why this could be happening? Any experience?

best regards,
Stephane

Read method without locals

I've compared the Read method with Unsafe implementation I used to use before. It's faster than Unsafe, but I found cases in my code where perf dropped by 9%. Without locals the perf improved as expected by 5% vs original or 14% vs the version with locals.

   [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static T Read<T>(object array, int index)
        where T : class
    {
        // IL.DeclareLocals(false, typeof(byte).MakeByRefType());
        //
        // Ldarg(nameof(array));
        // Stloc_0(); // convert the object pointer to a byref
        // Ldloc_0(); // load the object pointer as a byref

        Ldarga(nameof(array));
        Ldind_Ref();

Fir the Disruptor benchmark the performance is identical. My theory is that it's basically the same stuff, but with too many IL locals JIT sometimes gives up to optimize, or something from this genre. This particular benchmark was always very sensitive to locals even in the inlined method it does not directly go through.

BatchEventProcessor is not updating Sequence at correct point

The BatchEventProcessor.ProcessEvents() method isn't updating the sequence until all the events in the batch have been processed. This is blocking other consumers/producers from processing.
The blocked processes should be allowed to continue up to the event just processed within the batch or they will be spinning needlessly.
I have the fix for it but I do not have access to push a branch.

Is it safe/possible to use ByRefLike value types as events for ValueDisruptor?

I'm trying to avoid buffer allocations for my downstream ring buffer, which would in turn invoke a handler which encodes/serializes messages to clients. Messages are comprised of an array of entities at this point in application. So in contrast to my other ring buffers which also used ValueDisruptor and carry around single value type entities, I have a fixed length array of entities at this stage. I'm trying to switch all arrays with Span constructs and allocate the memory with stackalloc on the ring itself. This also enforces that the Disruptor event which embraces the Span should also be a ByRefLike type. But I'm not sure if this could work since whether me dynamically allocating with stackalloc collides with PublishEvent()/scope.Event() functionality and also that ByRefLike types are forced to always be handled on stack and many more restriction which frankly I do not have any idea if it would be respected though out inner workings of disruptor.

public ref struct SomeEvent                         // this is now ref struct
{
      ...
      public Span<SomeEntity> Items;          // change from SomeEntity[] Items
}

public struct SomeEntity
{
      ...
}

I'm trying to do this:

public void Produce(ref Span<SomEntity> messages)
{
      using var scope = disruptor.PublishEvent();
      ref var @event = ref scope.Event();
      @event.Items = stackalloc SampleEntity[fixedCount];
      messages.CopyTo(@event.Payload.Items);
}

Instead of something like this with normal structs:

public void Produce(ref Span<SomEntity> messages)
{
      using var scope = disruptor.PublishEvent();
      ref var @event = ref scope.Event();
      @event.Items = ArrayPool<SomeEntity>.Shared.Rent(fixedCount);
      messages.CopyTo(@event.Payload.Items);
}

Current solution on master is not building.

Hi,

shame on me, asking for a nuget package but never had opening the solution beforehand.
Now I tried to get it, but then while building the repository it missed a version.cs.

I could not find it in the repository. Soo, removing does the deal for compiling :)

Btw. thanks for keeping this repository up. It's a great example and in a way shows what possible.

Transfer of NuGet package ownership

Hi Olivier,
I don't know if you've been following, but I'm getting ready to release the 2.10.1 version of disruptor, which is the last version in the 2.x series...

  • Ported the java changes all the way till 2.10.1
  • Re-worked some of the build process scripts
  • Added more NuGet dependencies for all dependent libraries
  • ported most of the DisruptorTests from the java version that were missing in the .NET port (that uncovered a few inconsistencies BTW).
  • Added automatic Git information inside the .dll

I was wondering if you could add me as an owner to the NuGet package that you own:
https://www.nuget.org/packages/Disruptor/

(You need to sign in and click "manage owners", and add me, "damageboy").

Thanks!

Is there a way to ensure backpressure on producers and not overwrite?

I am using version 4.0.0 of Disruptor.

I have a single producer which is producing random numbers.

Right now I have a single handler which I want to consume the randomly generated numbers.

My payload object is

    public class RandomValue
    {
        public long value;
        public long counter;
    }

Where value is the random number and counter is a counter in the producer (which with one producer is always the same as the sequence number).

When I set up the disruptor and set it going, my consumer class is being fed very high sequence numbers.

Even making the ring buffer size a really small number, it's still getting a really high sequence number.

Also even with a small ring buffer size, the producer is not blocked on the Next call as I understand it should be.

My waitStrategy is BlockingWaitStrategy so I thought the producer call to Next was supposed to block when the ring is full, so how am I generating so many values in the producer before the consumer is consuming them?

Instead there's no back pressure at all on the producer.

I have tried to consume with both HandleEventsWithWorkerPool instead of HandleEventsWith and both have the same behaviour.

Error: Unknown command 'Build-Assembly'.

when you build using Cake-Build.bat I have received this error

Error: Unknown command 'Build-Assembly'.

   build\build.cake -target=Build-Assembly -configuration=Release -verbosity=Verbose
                            ^^^^^^^^^^^^^^ No such command

the solution is to edit this file build\build.ps1 line 188
Invoke-Expression "& "$CAKE_EXE" "$Script" --target="$Target" --configuration="$Configuration" --verbosity="$Verbosity" $UseMono $UseDryRun $UseExperimental $ScriptArgs";

solution source: cake-cli-updates

DataFlow Integration

There was an outstanding issue on google code to add support for .Net's new DataFlow library, has any work been done on this?

BlockingWaitStrategy is not blocking enough.

Hi! Found strange behavior. Sending a heartbeat message every second to a disruptor lead to 100% cpu load without any useful work.

Environment: AWS VM m4.large, 2 core 2.3GHz, Disruptor 3.3.5.1

Count of sent messages is 78 :

image

image

Is it a bug or by design?

Support for .NET-4.5.2?

Are there any plans to publish the nuget with support for .NET-4.5.2? Right now it is just a matter of recompiling it against the other framework version to make disruptor usable in .NET-4.5 applications.

Remove cake usage

Cake was introduced to automate builds, tests and packaging. Now those tasks can be simply performed using the dotnet command. The GitHub actions do not even use cake anymore.

Cake usage should be removed from the repository.

First 2 elements of ringBuffer are null

If I build in windows, and run in windows, it works fine.
However if I build in windows, and run using Mono on Linux, after I allocate my ringbuffer using:
var ringBuffer = disruptor.Start();
the 1st 2 elements of the array (index 0 and index 1) are null, the remainder are normal.

High CPU usage in wait strategies when waiting for dependent event handlers

All the wait strategies can generate high CPU usage when waiting for dependent handlers. While it is not an issue for CPU intensive strategies like BusySpinWaitStrategy, I believe it is not an expected behavior for synchronization based strategies like BlockingWaitStrategy.

The issue has been reported but will not be addressed in the Java version.

I see a few options here:

  1. Do not fix the issue in order to stay close to the Java version.
  2. Add new wait strategies to address the problem, for example BlockingWaitStrategyWithSpinWait.
  3. Add a constructor parameter to existing wait strategies, for example WaitForDependentSequenceMode.SpinWait (the default being WaitForDependentSequenceMode.BusySpin).
  4. Fix the issue in existing wait strategies, but use a very aggressive wait mode to minimize the impact. By "aggressive", I mean that the .NET SpinWait should be not be used to avoid Thread.Sleep(1).

I like option 4.

What do you think?

.NET 6 support

Will you please consider upgrading to .NET 6 compatibility. You use RuntimeHelpers.OffsetToStringData which has been deprecated and is unavailable in .NET 6.

Support .NET Standard / .NET Core

It appears this library only supports the full .NET Framework. Would it be possible to switch this to support a version of the .NET Standard so this library could be used in .NET Core applications?

DynamiclyAddHandler can't work

Disruptor-net/src/Disruptor.Samples/DynamiclyAddHandler.cs can't work
ps: I replaced Start with WaitUntilStarted(TimeSpan.Zero)

PerfTests won't run if no L3Cache...

I'm not sure that this is really a 'bug', but on my Xeon, apparently there is no L3 cache, so line 65 of PerfTests.Runner.ComputerSpecifications throws a ManagementException.

I've worked around it by putting try/catch around the line.

Just in case that might be useful for someone.

Replace .NET Core 1.1 target with .NET Standard 2.0

In Disruptor.csproj, the netcoreapp1.1 target can easily be replaced by netstandard2.0. The net45 target should be preserved because .NET Standard 2.0 requires .NET Framework 4.6.1.

The NETSTANDARD2_0 constant will become useless and should be removed.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.