Note that there are some explanatory texts on larger screens.

plurals
  1. POIs F# really faster than Erlang at spawning and killing processes?
    text
    copied!<p><em>Updated: This question contains an error which makes the benchmark meaningless. I will attempt a better benchmark comparing F# and Erlang's basic concurrency functionality and inquire about the results in another question.</em></p> <p>I am trying do understand the performance characteristics of Erlang and F#. I find Erlang's concurrency model very appealing but am inclined to use F# for interoperability reasons. While out of the box F# doesn't offer anything like Erlang's concurrency primitives -- from what I can tell async and MailboxProcessor only cover a small portion of what Erlang does well -- I've been trying to understand what is possible in F# performance wise.</p> <p>In Joe Armstrong's Programming Erlang book, he makes the point that processes are very cheap in Erlang. He uses the (roughly) the following code to demonstrate this fact:</p> <pre><code>-module(processes). -export([max/1]). %% max(N) %% Create N processes then destroy them %% See how much time this takes max(N) -&gt; statistics(runtime), statistics(wall_clock), L = for(1, N, fun() -&gt; spawn(fun() -&gt; wait() end) end), {_, Time1} = statistics(runtime), {_, Time2} = statistics(wall_clock), lists:foreach(fun(Pid) -&gt; Pid ! die end, L), U1 = Time1 * 1000 / N, U2 = Time2 * 1000 / N, io:format("Process spawn time=~p (~p) microseconds~n", [U1, U2]). wait() -&gt; receive die -&gt; void end. for(N, N, F) -&gt; [F()]; for(I, N, F) -&gt; [F()|for(I+1, N, F)]. </code></pre> <p>On my Macbook Pro, spawning and killing 100 thousand processes (<code>processes:max(100000)</code>) takes about 8 microseconds per processes. I can raise the number of processes a bit further, but a million seems to break things pretty consistently.</p> <p>Knowing very little F#, I tried to implement this example using async and MailBoxProcessor. My attempt, which may be wrong, is as follows:</p> <pre><code>#r "System.dll" open System.Diagnostics type waitMsg = | Die let wait = MailboxProcessor.Start(fun inbox -&gt; let rec loop = async { let! msg = inbox.Receive() match msg with | Die -&gt; return() } loop) let max N = printfn "Started!" let stopwatch = new Stopwatch() stopwatch.Start() let actors = [for i in 1 .. N do yield wait] for actor in actors do actor.Post(Die) stopwatch.Stop() printfn "Process spawn time=%f microseconds." (stopwatch.Elapsed.TotalMilliseconds * 1000.0 / float(N)) printfn "Done." </code></pre> <p>Using F# on Mono, starting and killing 100,000 actors/processors takes under 2 microseconds per process, roughly 4 times faster than Erlang. More importantly, perhaps, is that I can scale up to millions of processes without any apparent problems. Starting 1 or 2 million processes still takes about 2 microseconds per process. Starting 20 million processors is still feasible, but slows to about 6 microseconds per process.</p> <p>I have not yet taken the time to fully understand how F# implements async and MailBoxProcessor, but these results are encouraging. Is there something I'm doing horribly wrong?</p> <p>If not, is there some place Erlang will likely outperform F#? Is there any reason Erlang's concurrency primitives can't be brought to F# through a library?</p> <p>EDIT: The above numbers are wrong, due to the error Brian pointed out. I will update the entire question when I fix it.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload