2009-10-10 3 views
9

Ce qui suit est une fonction erlang. Je ne comprends pas comment les listes: fonction de carte est utilisée ici. Quelqu'un pourrait-il expliquer?comment utiliser les listes erlang: fonction de carte

% 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) }. 

Merci.

également, je ne connais pas la syntaxe correcte lors de l'utilisation de cette fonction. Par exemple, j'ai une fonction dummy() prendre 1 paramètre. J'ai une erreur en essayant de chronométrer la fonction dummy.

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

ci-dessus serait d'évaluer l'expression illégale.

En fait, maintenant avec la syntaxe correcte, la fonction peut être invoquée correctement:

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

Cependant, il lancera une exception en disant invoquant la fonction fictive sans passer aucun paramètre. Je pense que cette ligne est le méchant, [ G() || _ <- NN ], Je n'ai aucune idée de comment le réparer.

+1

Ce qui est la raison de 'G = fun() -> F(), ok end' au lieu d'appeler directement' F() 'NN fois? – Zed

+0

Ma première estimation était que c'était une optimisation erronée de "jeter" la sortie de F() au cas où en l'accumulant dans la compréhension de la liste, cela ralentissait les choses. Alors j'ai essayé et ça fait une différence! Si votre F produit quelque chose comme une liste de 255 entiers, alors l'exécuter assez souvent est plus lent dans une compréhension de liste que d'appeler G(). Peut-être est-ce dû aux frais généraux de construction de la liste. Utiliser les listes: foreach est une meilleure solution - c'est beaucoup plus rapide que la compréhension de la liste, et pas besoin d'imbriquer la fonction. –

Répondre

6

map est utilisé ici pour exécuter la fonction

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

pour chaque élément de MM. map retournera une nouvelle liste de la même taille, où chaque élément de la nouvelle liste est le résultat de l'application de la fonction ci-dessus à l'élément correspondant de MM.

Vous pouvez appeler time_it comme:

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). 

Avec ces:

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

du sens, maintenant?

1

Si vous avez une fonction moduleName: mannequin/1 vous pouvez faire une des opérations suivantes

  1. Si vous pouvez modifier time_it/3, puis faire appel F(constant_parameter) au lieu de F(). Je suppose que c'est le cas.
  2. Sinon, appelez le . dummy ne sera pas appelé directement, mais seulement par F à l'intérieur de time_it.
4

Le but de lists:map dans la fonction time_it est juste pour exécuter les temps la fonction interne M. Quand vous voyez ce modèle:

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

Cela signifie simplement appeler Foo() encore et encore M fois, et retourner les résultats de chaque appel dans une liste. Il fait en fait une liste d'entiers [1,2,3,...N] puis appelle Foo() une fois pour chaque membre de la liste.
L'auteur de time_it fait de nouveau cette même astuce, car time_it doit appeler la fonction que vous lui donnez N * M fois.Ainsi, à l'intérieur de la boucle externe qui fonctionne M fois qu'ils utilisent une technique différente pour exécuter les temps boucle interne N:

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

Cela a exactement le même résultat que le code ci-dessus, mais cette fois Foo est appelé N fois.

La raison pour laquelle vous avez des difficultés à utiliser time_it avec votre fonction fictive est que time_it prend une fonction avec 0 paramètres, non 1. Vous devez donc faire une fonction factice et l'appeler comme ceci:

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

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