I am trying to learn how to use the Disruptor.NET messaging framework, and I can't find any practical examples. There are quite a few articles out there with pictures about how it works, but I can't find anywhere that actually goes and shows you how to implement the methods. What would be an example?
Frustrated that I couldn't find a workable 'Hello World' for Disruptor-net, I fiddled around until I got one working - see below. Hopefully it's fairly self-explanatory. The Console.WriteLine lines are handy for seeing how things operate - for example, that the RingBuffer creates each entry instance at start-up (which makes sense).
Hope this helps anyone looking for help with Disruptor on .NET.
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Disruptor;
using Disruptor.Dsl;
namespace DisruptorTest
{
public sealed class ValueEntry
{
public long Value { get; set; }
public ValueEntry()
{
Console.WriteLine("New ValueEntry created");
}
}
public class ValueAdditionHandler : IEventHandler<ValueEntry>
{
public void OnNext(ValueEntry data, long sequence, bool endOfBatch)
{
Console.WriteLine("Event handled: Value = {0} (processed event {1}", data.Value, sequence);
}
}
class Program
{
private static readonly Random _random = new Random();
private static readonly int _ringSize = 16; // Must be multiple of 2
static void Main(string[] args)
{
var disruptor = new Disruptor.Dsl.Disruptor<ValueEntry>(() => new ValueEntry(), _ringSize, TaskScheduler.Default);
disruptor.HandleEventsWith(new ValueAdditionHandler());
var ringBuffer = disruptor.Start();
while (true)
{
long sequenceNo = ringBuffer.Next();
ValueEntry entry = ringBuffer[sequenceNo];
entry.Value = _random.Next();
ringBuffer.Publish(sequenceNo);
Console.WriteLine("Published entry {0}, value {1}", sequenceNo, entry.Value);
Thread.Sleep(250);
}
}
}
}
There is a detailed blog post on the Disruptor pattern, The Latency Issue. It demonstrates how to get started and use the Disruptor in detail.
Related
Why is it that Console.Writeline() will work when executing from a console app main() method; but when I execute the same using resharpers test runner I do not see the Console.Writeline() in the test runner output window?
The best way to explain this is with an example.
I am using: Resharper Ultimate 2017.1.3, Visual Studio 2017 Community, and .Net 4.6.1 framework. Language is C#. I also installed (via nuget) nunit framework 2.6.4.
First create a class library and copy paste the following in to a .cs file.
using System;
using System.Collections;
using System.Threading;
using NUnit.Framework;
namespace ObserverPatternExample
{
[TestFixture]
internal class ObserverTestFixture
{
[Test]
public void DemonstrateObserverPattern()
{
var subject = new Subject();
var a = new Observer(subject, "a");
var b = new Observer(subject, "b"); // etc. as many observers as you want.
subject.Go();
}
}
// "subject" is observer pattern lingo. The "subject" will do the broadcasting to the observers.
public class Subject
{
public delegate void CallbackHandler(string s);
public event CallbackHandler NotifyEvent;
private const int waitTimeInMilliseconds = 200;
private readonly Simulator simulator = new Simulator();
public string FakeSimulatorState { get; set; }
public void Go()
{
new Thread(Run).Start(); // a good thing to notice: events cross thread boundaries!!!
}
private void Run()
{
foreach (string s in simulator)
{
Console.WriteLine("Subject: " + s);
FakeSimulatorState = s;
NotifyEvent?.Invoke(s);
Thread.Sleep(
waitTimeInMilliseconds); // we do this to "pretend" that the simulator is actually doing someting.
}
}
}
public class Observer : IObserverPattern // the "observer" will subscribe to the event being broadcast by the "subject"
{
private readonly string _name;
public Observer(Subject subject, string name)
{
_name = name;
subject.NotifyEvent += Update;
}
public void Update(string state)
{
Console.WriteLine("Observer {0}: {1}", _name, state);
}
}
internal interface IObserverPattern
{
void Update(string state);
}
public class Simulator : IEnumerable
{
private readonly string[] _stateSequence = { "BEGIN", "CRAWL", "WALK", "JUMP", "END" };
public IEnumerator GetEnumerator()
{
foreach (var s in _stateSequence)
yield return s;
}
}
}
And now execute the test. I expect to see the Console.WriteLine() calls display strings in the Resharper test runner output window. But I don't. For example here is a screenshot:
Now let's perform the exact same sequence, but this time we'll call the client code from a new console project main() method. To set this up copy paste the following code and reference the class library you created in the steps above.
using ObserverPatternExample;
namespace ConsoleApp1
{
internal class Program
{
private static void Main(string[] args)
{
var subject = new Subject();
var a = new Observer(subject, "a");
var b = new Observer(subject, "b"); // etc. as many observers as you want.
subject.Go();
}
}
}
Next execute the console app. You should see the following displayed:
Can anyone please explain how I can configure either my code or the test runner to display the output in the test runner output window?
* UPDATE *
I made partial success. InBetween's suggestion to use a TraceListener made me realize I should be using a ConsoleTraceListener. To faciliate this I modified the unit test to appear like this:
using System.Threading;
using NUnit.Framework;
namespace ObserverPatternExample.DontUse
{
[TestFixture]
internal class ObserverTestFixture
{
[SetUp]
public void Setup()
{
Trace.Listeners.Add(new ConsoleTraceListener());
}
[TearDown]
public void TearDown()
{
Trace.Flush();
}
[Test]
public void DemonstrateObserverPattern()
{
var subject = new Subject();
var a = new Observer(subject, "a");
var b = new Observer(subject, "b"); // etc. as many observers as you want.
subject.Go();
}
}
And the results are surprising: I do get SOME output; but only the initial BEGIN state. Which appears like this:
Short story: I'm still looking for a solution.
*** SOLUTION ****
[Test]
public void DemonstrateObserverPattern()
{
var subject = new Subject();
var a = new Observer(subject, "a");
var b = new Observer(subject, "b"); // etc. as many observers as you want.
subject.Go();
Thread.Sleep(1000); // <--- add this to force test runner to wait for other thread to complete.
}
It looks like Resharper is finishing before your thread completes. Your call to
Thread(Run).Start();
is non-blocking. This means the test thread will complete before the Go thread does, hence you get no results.
See https://msdn.microsoft.com/en-us/library/6x4c42hc(v=vs.110).aspx where is states "Note that the call to Start does not block the calling thread."
I'm still trying to get the hang of this. The second part of my Main method will not execute. I believe I've called it correctly. But, obviously I didn't. A little help would be greatly appreciated!
using System;
using static System.Console;
using System.Threading;
namespace mellon_Assignment2
{
class Getting2KnowUapp
{
static void Main()
{
WriteLine("The current time is: " + DateTime.Now);
Thread.Sleep(2000);
AboutMe Me = new AboutMe();
}
}
}
using System;
using static System.Console;
using System.Threading;
namespace mellon_Assignment2
{
class AboutMe
{
public void DisplayInfo()
{
WriteLine("My Name\tAssignment 2");
Thread.Sleep(1500);
WriteLine("ITDEV110\tIntro to Object-oriented Programming");
Thread.Sleep(1500);
WriteLine("Professor\tSeptember 18th");
Thread.Sleep(1500);
}
}
}
You need to call DisplaInfo method. You are only creating the object and doing nothing with it:
AboutMe Me = new AboutMe();
Me.DisplayInfo();
Echoing the other replies, you aren't invoking the method on your class.
If you want it to occur when you create a new instance, you could move it into the constructor.
To do that, change:
public void DisplayInfo()
to
public AboutMe()
public void DisplayInfo() is it's own method and has to be called directly after initialization of the class AboutMe.
If you want the DisplayInfo() method to fire immediately upon initialization of AboutMe then simply add a constructor for AboutMe like so.
class AboutMe {
public AboutMe() {
DisplayInfo();
}
public void DisplayInfo() {
...
}
}
Then you can call:
AboutMe myvariable = new AboutMe();
I have several components in my C# code reading and setting key/value pairs in Redis in a multi-threaded context. The following minimal example
using System;
using System.Threading;
//Uncomment one of these two
//using CSRedis;
using Sider;
namespace FailureTesting
{
class UsingRedis
{
static RedisClient client = new RedisClient("localhost");
static void Main(string[] args)
{
Thread read = new Thread(Reader);
Thread set = new Thread(Setter);
read.Start();
set.Start();
}
static void Reader()
{
while(true)
{
client.Get("key");
}
}
static void Setter()
{
while (true)
{
client.Set("key", "value");
}
}
}
}
throws an Unhandled exception with Additional information: Expecting a Bulk reply, got instead69reply which makes me think that the pipe between C# and Redis is saturated. This occurs wether I use CSRedis or Sider.
On the other hand, if I use a second client, that is a second pipe for the Setter method, then everything works fine (setting static RedisClient client2 = new RedisClient("localhost"); and then client2.Set(...))
Finally, using the StackExchange.Redis library with the following equivalent code
using System;
using System.Threading;
using StackExchange.Redis;
namespace FailureTesting
{
class TestingSider
{
static IDatabase db = ConnectionMultiplexer.Connect("localhost:6379").GetDatabase();
static void Main(string[] args)
{
Thread read = new Thread(Reader);
Thread set = new Thread(Setter);
read.Start();
set.Start();
}
static void Reader()
{
while (true)
{
db.StringGet("key");
}
}
static void Setter()
{
while (true)
{
db.StringSet("key", "value");
}
}
}
}
then everything works well. The problem I have is that the StackExchange library is only supported by .NET Framework 4.5 while I have to use .Net Framework 4.0.
Could someone give me some insights about what happens here? I don't want to put locks or mutex in my code while Redis guarantees that all the operations are atomic...
I keep trying to make this C# program work, but I keep getting an Error about the constructor taking 1 argument. I don't get it. I think it has to do with the " Test myTest = new Test(3);" but I don't know what to do with it.
Any help or steering me in the right direction would be greatly appreciated. Thank you.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
public class Test
{
private int tally;
public void Test(int start)
{
tally = start;
}
public void AddFive()
{
tally += 5;
}
public void Display()
{
Console.WriteLine("The tally is {0}", tally);
}
public void Main(string[] args)
{
Test myTest = new Test(3);
myTest.AddFive();
myTest.Display ();
}
}
}
Constructors don't have return type.
So instead of
public void Test(int start)
{
tally = start;
}
you should have
public Test(int start)
{
tally = start;
}
In the constructor definition you said to return void. That is not required. Your constrctor should be
public Test(int strat)
{
...
}
I am new to threading, so please forgive me if my question is at an amateur level.The example below is a simplified version of what I am trying to do. This works if method go is static, I want it to work when Go is not static. How do I make it work.
using System;
using System.Threading;
using System.Diagnostics;
public class ThreadPoolExample
{
static void Main()
{
for (int i = 0; i < 10; i++)
{
ThreadPool.QueueUserWorkItem(Go, i);
}
Console.ReadLine();
}
void Go(object data)
{
Console.WriteLine(data);
}
}
If someone can make this work and add a notification that all threads have completed execution, that would be awesome.
I suspect there it has nothing to do with Go being static or not, but rather the fact that you can't call/use instance method "Go" from static "Main". Either both need to be static or you need to call/use Go on an instance of your class like:
ThreadPool.QueueUserWorkItem(value => new ThreadPoolExample().Go(value), i);
Do it in this way
class ThreadPoolExample
{
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
ThreadPoolExample t = new ThreadPoolExample();
ThreadPool.QueueUserWorkItem(t.Go, i);
}
Console.ReadLine();
}
void Go(object data)
{
Console.WriteLine(data);
}
}