2009-10-10 16 views
9

Poniżej znajduje się funkcja erlang. Nie rozumiem, w jaki sposób używa się list: funkcja map. Czy ktoś mógłby wyjaśnić?sposób korzystania z list erlang: funkcja mapy

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

Dzięki.

również, nie znam prawidłowej składni podczas korzystania z tej funkcji. Na przykład mam funkcję dummy() przyjmuję 1 parametr. Wystąpił błąd podczas próby wyzerowania funkcji fikcyjnej.

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

powyższe będzie oceniać jako nielegalne wyrażenie.

Właściwie teraz z poprawną składnią, funkcja może być wywołana poprawnie:

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

Będzie jednak rzucić wyjątek mówiący wywoływanie funkcji manekina bez przechodzenia dowolny parametr. Myślę, że ta linia to złoczyńca, [ G() || _ <- NN ], Nie mam pojęcia, jak to naprawić.

+1

Co powód "G = fun() -> F(), ok koniec" zamiast bezpośredniego wywoływania 'F()' NN razy? – Zed

+0

Moim początkowym założeniem było to, że była to błędna optymalizacja, która "wyrzuci" wyjście F() na wszelki wypadek, gromadząc je na liście, co spowolniło. Więc spróbowałem i to robi różnicę! Jeśli twoje F wypisze coś w rodzaju listy 255 liczb całkowitych, to uruchomienie go wystarczająco długo jest wolniejsze w zrozumieniu listy niż wywołanie G(). Być może wynika to z napowietrznej budowy listy. Korzystanie z list: foreach jest lepszym rozwiązaniem - jest to znacznie szybsze niż zrozumienie listy i nie ma potrzeby zagnieżdżania funkcji. –

Odpowiedz

6

map jest tutaj stosowane do wykonania funkcji

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

dla każdego elementu MM. map zwróci nową listę o tym samym rozmiarze, gdzie każdy element nowej listy jest wynikiem zastosowania powyższej funkcji do odpowiedniego elementu z MM.

Można powołać time_it jak:

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

Tymi:

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

sensu, teraz?

1

Jeśli masz modulename funkcję: atrapę/1 można wykonać jedną z następujących czynności

  1. Jeśli można edytować time_it/3, a następnie zrobić to zadzwonić F(constant_parameter) zamiast F(). Zakładam, że tak jest.
  2. W przeciwnym razie zadzwoń pod numer M1:time_it(fun() -> M2:dummy(constant_parameter) end, N, M). manekin nie będzie wywoływany bezpośrednio, ale tylko przez F w time_it.
4

Celem lists:map w funkcji time_it jest tylko uruchomienie funkcji wewnętrznej M razy. Kiedy widzisz ten wzór:

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

Oznacza to tylko zadzwonić Foo() znowu i znowu M razy i powrót wyników każdego połączenia na liście. W rzeczywistości tworzy listę liczb całkowitych [1,2,3,...N], a następnie wywołuje Foo() jeden raz dla każdego członka listy.
Autor time_it ponownie wykonuje tę samą sztuczkę, ponieważ time_it musi wywołać funkcję, którą mu się nadajesz N * M razy.Więc wewnątrz pętli zewnętrznej, która biegnie m Czas oni użyć innej techniki, aby uruchomić wewnętrzne razy pętla N:

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

ten ma dokładnie taki sam wynik jak w powyższym kodzie, ale tym razem Foo nazywa się N razy.

Powodem masz problemy z korzystaniem time_it z manekina funkcji jest to, że time_it wykonuje funkcję z 0 parametrach nie 1. Więc trzeba zrobić manekina funkcji i nazwać tak:

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

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