Simulate Ring of Actors
This is a naive implementation that explores the idea of simulating a ring of N
actors that send the messages to each over M
times.
Concept of the ring benchmark and simulated actors is taken from the gist by Preetam Jinka.
The implementation is quite simple and allows us to focus on core concepts:
- messages used for the communication;
- actors representing individual processes;
- simulation environment
- simulation loop.
Implementation
Let's start by defining a message and a simulation environment to hold a global inbox.
public struct Message {
public readonly int Recipient;
public readonly object Body;
public Message(int recipient, object body) {
Recipient = recipient;
Body = body;
}
}
public sealed class Env {
readonly Queue<Message> _messages = new Queue<Message>();
public void Send(int recipient, object message) {
_messages.Enqueue(new Message(recipient, message));
}
public bool GetNextMessage(out Message msg) {
return _messages.TryDequeue(out msg);
}
}
Actor is a class that has a recipient and can send a message to it:
public class Actor {
readonly int NextActor;
int _counter;
readonly Env _env;
readonly int _m;
public Actor(int nextActor, Env env, int m) {
NextActor = nextActor;
_env = env;
_m = m;
}
public void HandleMessage(object message) {
_counter++;
if (_counter <= _m) {
_env.Send(NextActor, message);
}
}
}
We can join everything together by the actual simulation loop. It sets up a ring of actors and then sends the first message.
class Program {
static void Main(string[] args) {
const int n = 1000;
const int m = 1000;
var actors = new List<Actor>();
var env = new Env();
for (int i = 0; i < n; i++) {
var next = (i + 1) % n;
actors.Add(new Actor(next, sim, m));
}
env.Send(0, new {hello = "world"});
var watch = Stopwatch.StartNew();
while (env.GetNextMessage(out var msg)) {
actors[msg.Recipient].HandleMessage(msg.Body);
}
Console.WriteLine(watch.Elapsed);
}
}
Given N=1000
and M=1000
, the result on my machine is:
dotnet SimRing.dll
00:00:00.0260680
Questions
- How would you implement a ring benchmark in golang?
- This .NET Core implementation is way faster than Erlang. What does Erlang spend time on?
- Why is this implementation faster than FoundationDB Flow? What extra work could the Flow do?
Next post in Simulation story: Simulate with Async
🤗 Check out my newsletter! It is about building products with ChatGPT and LLMs: latest news, technical insights and my journey. Check out it out