Actors in F#
It’s been a while since I posted anything here, mainly because we’ve been busy on the Axum team blog over the last few weeks and months. Inspired by this post by Matthew Podwysocki, I thought it would be interesting to show actors in F#, which are closely related to the Axum model.
PingPong is a fairly common micro-benchmark for message-passing: it is used because it measures the pure overhead of passing messages, with the logic in the actors doing no interesting work. It is a trivial piece of code, but very educational in that it shows a very simple framework for creating actors that go back and forth synchronizing their work. It is easy to expand on, etc.
Matthew’s blog shows the Erlang code and then the Axum code. Let’s also consider F#, which like Erlang has built-in support for actors, and comes from a functional tradition. The PingPong example looks like this in F#:
open System
type message = Finished | Msg of int * MailboxProcessor<message>
let ping iters (outbox : MailboxProcessor<message>) =
MailboxProcessor.Start(fun inbox ->
let rec loop n = async {
if n > 0 then
outbox.Post( Msg(n, inbox) )
let! msg = inbox.Receive()
Console.WriteLine("ping received pong")
return! loop(n-1)
else
outbox.Post(Finished)
Console.WriteLine("ping finished")
return ()}
loop iters)
let pong () =
MailboxProcessor.Start(fun inbox ->
let rec loop () = async {
let! msg = inbox.Receive()
match msg with
| Finished ->
Console.WriteLine("pong finished")
return ()
| Msg(n, outbox) ->
Console.WriteLine("pong received ping")
outbox.Post(Msg(n, inbox)
return! loop() }
loop())
let ponger = pong()
do (ping 10 ponger) |> ignore
The structure and amount of code in this example is very similar to the Erlang code and is similarly hard/easy to read, depending on your perspective.
The mailbox processor design follows the traditional actor-oriented pattern and is therefore a bit different than the approach we’re taking in Axum. Notice that rather than establishing a channel between ping and pong, we’re sending the mailbox to the other side with each message.
One of the advantages of this model over the Axum model is that any number of clients can communicate with an actor, all that is needed is access to the mailbox reference. This means that one single pong actor can service the requests of many ping actor, at least if the implementation is completely stateless.
The mailbox model also has some disadvantages: it is hard to reason and orchestrate the interactions between n client actors when you cannot distinguish them, and any hint of statefulness ruins the scenario. In the pong case, the state we have is whether the ‘Finished’ message has been received. Once one pinger sends it, pong will stop servicing others, who will never know. In the channel model, there’s an explicit agreement between only two parties on how they both will behave, an agreement that can be checked at runtime and, in many cases, at compile time.
Another annoyance is that mailboxes do not have any clear endpoints – I can create a mailbox and start receiving messages from it. With the channel model, each side of the channel is unique and the type system takes care of separating them: you send from one and receive from the other, and ne’er the twain shall be confused.
As you can tell, I have a certain bias, but that doesn’t mean I’m down on the F# model. In fact, I love F# and hope there is a way we can combine its conciseness with the, in my humble opinion, safer Axum model for channel-based communication.
You should download and try Axum, but do also play with F# and its actor-based API. I’d love to hear your analysis of the relative strengths and weaknesses of the two models.
Niklas
Comments
- Anonymous
May 12, 2009
PingBack from http://asp-net-hosting.simplynetdev.com/actors-in-f/ - Anonymous
May 12, 2009
Thank you for submitting this cool story - Trackback from DotNetShoutout - Anonymous
May 14, 2009
  In the previous post , I gave the canonical Ping-Pong example in Axum and how it compared with - Anonymous
May 15, 2009
In the previous post , I gave the canonical Ping-Pong example in Axum and how it compared with Axum. - Anonymous
May 17, 2009
A bit of a slow week.  Perhaps some are out playing in the recently fantastic weather instead of - Anonymous
May 20, 2009
The comment has been removed - Anonymous
May 20, 2009
Ivan,You're right -- the code I posted is missing a final 'do Console.ReadLine()' that will keep the process alive until the work finishes. That's what I actually used to run the code myself, but somehow it was omitted in the code above.Niklas - Anonymous
May 29, 2009
My fellow programming language enthusiast Matthew Podwysocki just posted another F#-based actor sample