2009-10-10 11 views
9

La siguiente es una función de erlang. No entiendo cómo se usan las listas: función de mapa aquí. ¿Podría alguien explicar?cómo usar las listas de erlang: función de mapa

% perform M runs with N calls to F in each run. 
% For each of the M runs, determine the average time per call. 
% Return, the average and standard deviation of these M results. 

time_it(F, N, M) -> 
     G = fun() -> F(), ok end, 
     NN = lists:seq(1, N), 
     MM = lists:seq(1, M), 
     T = lists:map(
      fun(_) -> 
      T0 = now(),    % start timer 
      [ G() || _ <- NN ],   % make N calls to F 
      1.0e-6*timer:now_diff(now(), T0)/N % average time per call 
     end, 
     MM 
     ), 
     { avg(T), std(T) }. 

Thanks.

Además, no conozco la sintaxis correcta al usar esta función. Por ejemplo, tengo una función ficticia() toma 1 parámetro. Obtengo un error al intentar cronometrar la función ficticia.

moduleName:time_it(moduleName:dummy/1, 10, 100). 

lo anterior evaluarían la expresión ilegal.

En realidad, ahora con la sintaxis correcta, la función puede ser invocada correctamente con:

moduleName:time_it(fun moduleName:dummy/1, 10, 100). 

Sin embargo, se producirá una excepción diciendo que invoca la función ficticia sin pasar ningún parámetro. Creo que esta línea es la villana, [ G() || _ <- NN ], No tengo ni idea de cómo solucionarlo.

+1

Lo que es el motivo de 'G = fun() -> F(), ok end' en lugar de llamar directamente a' F() 'NN veces? – Zed

+0

Mi conjetura inicial fue que esta era una optimización equivocada para "tirar" la salida de F() en caso de que al acumularla en la lista de comprensión disminuyera la velocidad. ¡Así que lo probé y marca la diferencia! Si su F produce algo así como una lista de 255 enteros, entonces ejecutarla basta veces es más lento dentro de una lista de comprensión que llamar a G(). Tal vez esto se deba a la sobrecarga de la creación de la lista. Uso de listas: Foreach es una solución mejor, esto es mucho más rápido que la comprensión de la lista, y no es necesario anidar la función. –

Respuesta

6

map se utiliza aquí para ejecutar la función

T0 = now(),       % start timer 
[ G() || _ <- NN ],     % make N calls to F 
1.0e-6*timer:now_diff(now(), T0)/N % average time per call 

para cada elemento de MM. map devolverá una nueva lista del mismo tamaño, donde cada elemento de la nueva lista es el resultado de aplicar la función anterior al elemento correspondiente de MM.

Puede invocar time_it como:

moduleName:time_it(fun moduleName:dummy/1, 10, 100). 
0
results(N, F) when N >= 0 -> results(N, F, []). 
results(0, _, Acc) -> lists:reverse(Acc); 
results(N, F, Acc) -> results(N-1, F, [F() | Acc]). 

repeat(0, F) -> ok; 
repeat(N, F) when N > 0 -> 
    F(), 
    repeat(N-1, F). 

Con estas:

T = results(M, fun() -> 
        T0 = now(), 
        repeat(N, G), 
        1.0e-6 * timer:now_diff(now(), T0)/N 
       end) 

tiene sentido, ahora?

1

Si usted tiene una función ModuleName: maniquí/1 se puede hacer una de las siguientes

  1. Si puede editar time_it/3, a continuación, hacer que llamar en lugar de F(constant_parameter)F(). Supongo que este es el caso.
  2. De lo contrario, llame al M1:time_it(fun() -> M2:dummy(constant_parameter) end, N, M). dummy no se llamará directamente, sino solo por F dentro de time_it.
4

El propósito de lists:map en la función time_it es simplemente ejecutar la función interna M veces. Cuando vea este patrón:

L = lists:seq(1,M), 
lists:map(fun(_)-> Foo() end, L) 

Sólo significa llamar Foo() una y otra vez M veces, y devolver los resultados de cada llamada en una lista. De hecho, hace una lista de enteros [1,2,3,...N] y luego llama al Foo() una vez por cada miembro de la lista.
El autor de time_it hace esto mismo truco de nuevo, porque time_it tiene que llamar a la función que le des N * M veces.Así que en el interior del bucle externo que se ejecuta M veces que utilizan una técnica diferente para ejecutar las bucle N veces interiores:

L = lists:seq(1,N), 
[Foo() || _ <- L] 

Esto tiene exactamente el mismo resultado que el código anterior, pero esta vez Foo se llama N veces.

La razón por la que tiene algún problema usando time_it con su función ficticia es que time_it toma una función con 0 parámetros y no por 1. Así que hay que hacer una función maniquí y lo llaman así:

dummy() -> 
    %% do something here you want to measure 
    ok. 

measure_dummy() -> 
    time_it(fun someModule:dummy/0, 10, 100). 
Cuestiones relacionadas