Actors prototype in C#

Attached is a rough outline of actors, or message passing concurrency, for C#. It is similar in spirit to Erlang. The basic idea is that each actor is a thread that blocks on a queue. It simply grabs an element from the queue, processes it and sends messages to other actors, and then waits for another message.

This code uses threads but I’d rather use Tasks in .NET 4.0, which would likely scale much better. The signature of the handler is not good. It returns “true” to continue processing messages, and “false” to end the actor. There is no error handling anywhere. What happens when the actor is finished but people keep sending messages? I don’t know what happens in Erlang, but there needs to be an exception or something. Otherwise, this code basically works. I can probably implement most of the Erlang samples with this class.

using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using System.Threading;

namespace Concurrency.Actors
{
    public interface IActor<T>
    {
        void Send(T message);
    }

    public class Actor<T> : IActor<T>
    {
        private BlockingCollection<T> _inbox = new BlockingCollection<T>();
        private Func<T, bool> _handler;
        private Thread _manager;

        private void Manager()
        {
            while (_handler(_inbox.Take())) ;
        }

        public void Send(T message)
        {
            _inbox.Add(message);
        }

        private Actor(string n, Func<T, bool> h)
        {
            _handler = h;
            _manager = new Thread(Manager);
            _manager.Name = n;
            _manager.Start();
        }

        public static IActor<T> Spawn(string name, Func<T, bool> handler)
        {
            return new Actor<T>(name, handler);
        }
    }
}

5 comments

  1. Bartosz Milewski

    In Erlang, actors may receive polymorphic messages. They are handled using pattern matching. In your implementation an actor may only receive one type of message. You’d have to use some kind of variant to be able to stuff different types of messages into one message type that is accepted by Send. The client would have to write a custom _handler to do the matching and casting. To my knowledge, there is no clean way to write a generic type-matching handler in C#.

    • Pinku

      Correct, the messages are strongly typed because C# is a statically typed language. Concurrent ML also use typed messages, as do other actor libraries. Unfortunately, the syntax for variants in C# is cumbersome, but F# is just fine.

  2. Bartosz Milewski

    Indeed, Concurrent ML’s abstraction is a strongly typed Channel. However, they can compose multiple channels, essentially creating a polymorphic message queue. Actors are not composable in that way (can’t block waiting on multiple Actors).

    F# (and also Scala) have built-in pattern matching, so they have no problem with multi-typed messages.

    • Pinku

      I think the main issue is that C# does not have convenient syntax for variants like F# and other functional languages. The user would have to provide a handler for every new Actor (see Actor.Spawn) and deal with variants the gross C# way (inheritance).

      CML’s choose operation has the signature: ‘a event list -> ‘a event. So you can wait on multiple channels, but they must all be type ‘a. Again, this is easy in SML, verbose in C# and untyped in Erlang (easy but unsafe).

  3. Bartosz Milewski

    The way to compose events of different types in CML is to use

    wrap : ’a event -> (’a -> ’b) -> ’b event

    and then “choose” between wrapped events. You could probably do a similar thing with lambdas in C#.

Leave a comment