Actualizado: Esta pregunta contiene un error que hace que el punto de referencia no tenga sentido. Intentaré un mejor punto de referencia comparando la funcionalidad de concurrencia básica de F # y Erlang e investigaré los resultados en otra pregunta.¿Es F # realmente más rápido que Erlang en los procesos de desove y muerte?
Estoy tratando de entender las características de rendimiento de Erlang y F #. Encuentro el modelo de simultaneidad de Erlang muy atractivo, pero me inclino a usar F # por razones de interoperabilidad. Mientras que F # no ofrece nada como las primitivas de simultaneidad de Erlang, de lo que puedo decir como asincronía y MailboxProcessor solo cubre una pequeña porción de lo que Erlang hace bien, he estado tratando de entender qué es posible en el rendimiento de F #. sabio.
En el libro Programación Erlang de Joe Armstrong, señala que los procesos son muy baratos en Erlang. Él usa la (más o menos) el siguiente código para demostrar este hecho:
-module(processes).
-export([max/1]).
%% max(N)
%% Create N processes then destroy them
%% See how much time this takes
max(N) ->
statistics(runtime),
statistics(wall_clock),
L = for(1, N, fun() -> spawn(fun() -> wait() end) end),
{_, Time1} = statistics(runtime),
{_, Time2} = statistics(wall_clock),
lists:foreach(fun(Pid) -> Pid ! die end, L),
U1 = Time1 * 1000/N,
U2 = Time2 * 1000/N,
io:format("Process spawn time=~p (~p) microseconds~n",
[U1, U2]).
wait() ->
receive
die -> void
end.
for(N, N, F) -> [F()];
for(I, N, F) -> [F()|for(I+1, N, F)].
en mi MacBook Pro, el desove y matando a 100 mil procesos (processes:max(100000)
) tarda unos 8 microsegundos por procesos. Puedo aumentar el número de procesos un poco más, pero un millón parece romper las cosas de forma bastante consistente.
Conociendo muy poco F #, intenté implementar este ejemplo usando async y MailBoxProcessor. Mi intento, que puede estar equivocado, es el siguiente:
#r "System.dll"
open System.Diagnostics
type waitMsg =
| Die
let wait =
MailboxProcessor.Start(fun inbox ->
let rec loop =
async { let! msg = inbox.Receive()
match msg with
| Die -> 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."
usuario de F # en Mono, con salida y matando a 100.000 actores/procesadores toma menos de 2 microsegundos por proceso, aproximadamente 4 veces más rápido que Erlang. Más importante aún, quizás, es que puedo escalar hasta millones de procesos sin ningún problema aparente. Comenzar 1 o 2 millones de procesos todavía toma aproximadamente 2 microsegundos por proceso. El inicio de 20 millones de procesadores sigue siendo factible, pero se desacelera a aproximadamente 6 microsegundos por proceso.
Todavía no me he tomado el tiempo para comprender completamente cómo F # implementa async y MailBoxProcessor, pero estos resultados son alentadores. ¿Hay algo que estoy haciendo terriblemente mal?
Si no, ¿hay algún lugar donde Erlang probablemente supere F #? ¿Hay alguna razón por la que las primitivas de simultaneidad de Erlang no puedan ser llevadas a F # a través de una biblioteca?
EDITAR: Los números anteriores son incorrectos, debido al error que señaló Brian. Actualizaré toda la pregunta cuando la solucione.
+1 para una pregunta verdaderamente avanzada. – gahooa
+1 para ser interesante también y no solo avanzado. – gradbot
has usado la opción "erl + native" para Erlang? (ver http://stackoverflow.com/questions/2207451/erlang-compilation-mixed-of-hipe-object-code-and-opcode) – jldupont