Practical ASP.NET

Distributed Concurrent Actor Models with Akka.NET

Ease the pain of concurrent programming with the Actor Model and Akka.NET.

Building concurrent systems that are capable of working on multiple pieces of work at the same time can be difficult, particularly when there's some shared mutable state being accessed by multiple threads.

The Actor Model gives you a way of representing systems using the higher-level abstractions of actors and messages. This can ease the burden of building concurrent systems.

Akka.NET is a port of the original Akka framework from Java/Scala to the Microsoft .NET Framework.

The Actor Model
The Actor Model describes a system whereby the fundamental unit of computation is the actor. A collection of actors performs the work of the system. Actors do not expose their internal state to the outside world (including other actors) but instead communicate via messages. The idea of this approach is to remove any shared mutable state; while actors do have mutable (internal) state, messages should be immutable.

An actor is able to do four essential things:

  • Respond to messages sent to it
  • Send messages to other actors
  • Create new actors
  • Change its behaviour in response to an incoming message

In Akka.NET, actors are classes that inherit from specific Akka.NET base classes, while messages can be simple .NET types such as a string, and they can also be custom types that are simple POCO classes.

Actors may exist in the same process on the same machine, different processes on the same machine, or even in different processes on different machines across the network. This ability to distribute actors out across multiple machines enables a system to scale out as required. One important feature in Akka.NET is that the code you write in your actors doesn't need to change depending on whether you're sending messages to a remote or local actor.

Defining an Akka.NET Actor
There is a choice of Akka.NET base classes to inherit from when defining an actor class, the basic being the untyped actor API. To get access to the core Akka.NET features the "Akka" NuGet package is installed.

In Listing 1 you can see an actor that's able to handle string or int messages that are sent to it.

Listing 1: Simple Actor Class Using the Untyped API
public class DemoActor : UntypedActor
{
  protected override void OnReceive(object message)
  {
    if (message is string)
    {
      // Do something with string message
      Console.WriteLine("Received string message {0}", message);
    }
    if (message is int)
    {
      // Do something with int message
      Console.WriteLine("Received int message {0}", message);
    }
    else
    {
      Unhandled(message);
    }
  }
}

An Actor System
In Akka.NET, actors live inside a managed actor system. This actor system manages the creation and lifetime of actors and the sending of messages around the system.

In Listing 2 you can see the Main method of a console application that creates an actor system, populates it with an actor instance and then sends a message to the actor using the Tell method.

Listing 2: Creating Actor Systems and Actor Instances
class Program
{
  static void Main(string[] args)
  {
    var actorSystem = ActorSystem.Create("DemoSystem");

    var actorReference = actorSystem.ActorOf<DemoActor>("DemoActor1");

    actorReference.Tell("hello");
    actorReference.Tell(123);

    // Wait for enter before closing console application
    Console.ReadLine();
  }
}

The output of running this code is shown in Figure 1.

[Click on image for larger view.] Figure 1. Console Application Showing Messages Being Received and Processed

Using Receive Actors
Receive actors offer a higher level API that does not require the kind of "if (message is string)" type statements. Instead the actor class inherits from the ReceiveActor base class and uses its Receive method to specify what types of messages it can handle. In Listing 3 we can see the same actor from Listing 1 refactored to a receive actor.

Listing 3: Inheriting from ReceiveActor
public class DemoActor : ReceiveActor
{
  public DemoActor()
  {
    Receive<string>(message =>
      {
        // do something with string message
        Console.WriteLine("Received string message {0}", message);
      });

    Receive<int>(message =>
      {
        // do something with int message
        Console.WriteLine("Received int message {0}", message);
      });
  }
}

This produces the same output when executed in the console application.

To find out more about Akka.NET, check out the project homepage at getakka.net.

About the Author

Jason Roberts is a Microsoft C# MVP with over 15 years experience. He writes a blog at http://dontcodetired.com, has produced numerous Pluralsight courses, and can be found on Twitter as @robertsjason.

comments powered by Disqus

Featured

Subscribe on YouTube