title: MailboxProcessor performance problems
body: <p>I have been trying to design a system which allows a large amount of concurrent users to be represented in memory at the same time. When setting out to design this sytem I immediately thought of some sort of actor based solution a kin to Erlang. </p>
  
  <p>The system has to be done in .NET, so I started working on a prototype in F# using MailboxProcessor but have run into serious performance problems with them. My initial idea was to use one actor (MailboxProcessor) per user to serialize communication the communication for one user.</p>
  
  <p>I have isolated a small piece of code that reproduces the problem I am seeing:</p>
  
  <pre><code>open System.Threading;
  open System.Diagnostics;
  
  type Inc() =
  
      let mutable n = 0;
      let sw = new Stopwatch()
  
      member x.Start() =
          sw.Start()
  
      member x.Increment() =
          if Interlocked.Increment(&amp;n) &gt;= 100000 then
              printf "UpdateName Time %A" sw.ElapsedMilliseconds
  
  type Message
      = UpdateName of int * string
  
  type User = {
      Id : int
      Name : string
  }
  
  [&lt;EntryPoint&gt;]
  let main argv = 
  
      let sw = Stopwatch.StartNew()
      let incr = new Inc()
      let mb = 
  
          Seq.initInfinite(fun id -&gt; 
              MailboxProcessor&lt;Message&gt;.Start(fun inbox -&gt; 
  
                  let rec loop user =
                      async {
                          let! m = inbox.Receive()
  
                          match m with
                          | UpdateName(id, newName) -&gt;
                              let user = {user with Name = newName};
                              incr.Increment()
                              do! loop user
                      }
  
                  loop {Id = id; Name = sprintf "User%i" id}
              )
          ) 
          |&gt; Seq.take 100000
          |&gt; Array.ofSeq
  
      printf "Create Time %i\n" sw.ElapsedMilliseconds
      incr.Start()
  
      for i in 0 .. 99999 do
          mb.[i % mb.Length].Post(UpdateName(i, sprintf "User%i-UpdateName" i));
  
      System.Console.ReadLine() |&gt; ignore
  
      0
  </code></pre>
  
  <p>Just creating the 100k actors take around 800ms on my quad core i7. Then submitting the <code>UpdateName</code> message to each one of the actor and wait for them to complete takes about 1.8 seconds. </p>
  
  <p>Now, I realize there is overhead from all the queue:ing on the ThreadPool, setting/resetting AutoResetEvents, etc internally in the MailboxProcessor. But is this really the expected performance? From reading both MSDN and various blogs on the MailboxProcessor I have gotten the idea that it's to be a kin to erlang actors, but from the abyssmal performance I am seeing this doesn't seem to hold true in reality? </p>
  
  <p>I also tried a modified version of the code, which uses 8 MailboxProcessors and each one of them hold a <code>Map&lt;int, User&gt;</code> map which is used to lookup a user by id, it yielded some improvements bringing down the total time for the UpdateName operation to 1.2 seconds. But it still feels very slow, the modified code is here:</p>
  
  <pre><code>open System.Threading;
  open System.Diagnostics;
  
  type Inc() =
  
      let mutable n = 0;
      let sw = new Stopwatch()
  
      member x.Start() =
          sw.Start()
  
      member x.Increment() =
          if Interlocked.Increment(&amp;n) &gt;= 100000 then
              printf "UpdateName Time %A" sw.ElapsedMilliseconds
  
  type Message
      = CreateUser of int * string
      | UpdateName of int * string
  
  type User = {
      Id : int
      Name : string
  }
  
  [&lt;EntryPoint&gt;]
  let main argv = 
  
      let sw = Stopwatch.StartNew()
      let incr = new Inc()
      let mb = 
  
          Seq.initInfinite(fun id -&gt; 
              MailboxProcessor&lt;Message&gt;.Start(fun inbox -&gt; 
  
                  let rec loop users =
                      async {
                          let! m = inbox.Receive()
  
                          match m with
                          | CreateUser(id, name) -&gt;
                              do! loop (Map.add id {Id=id; Name=name} users)
  
                          | UpdateName(id, newName) -&gt;
                              match Map.tryFind id users with
                              | None -&gt; 
                                  do! loop users
  
                              | Some(user) -&gt;
                                  incr.Increment()
                                  do! loop (Map.add id {user with Name = newName} users)
                      }
  
                  loop Map.empty
              )
          ) 
          |&gt; Seq.take 8
          |&gt; Array.ofSeq
  
      printf "Create Time %i\n" sw.ElapsedMilliseconds
  
      for i in 0 .. 99999 do
          mb.[i % mb.Length].Post(CreateUser(i, sprintf "User%i-UpdateName" i));
  
      incr.Start()
  
      for i in 0 .. 99999 do
          mb.[i % mb.Length].Post(UpdateName(i, sprintf "User%i-UpdateName" i));
  
      System.Console.ReadLine() |&gt; ignore
  
      0
  </code></pre>
  
  <p>So my question is here, am I doing something wrong? Have I missunderstood how the MailboxProcessor is supposed to be used? Or is this performance what is expected.</p>
  
  <p><strong>Update:</strong></p>
  
  <p>So I got a hold of some guys on ##fsharp @ irc.freenode.net, which informed me that using sprintf is very slow, and as it turns out that is where a large part of my performance problems were comming from. But, removing the sprintf operations above and just using the same name for every User, I still end up with about 400ms for doign the operations, which feels really slow.</p>