2009-10-10 3 views
9

Следующая функция erlang. Я не понимаю, как используются списки: функция map. Не мог бы кто-нибудь объяснить?как использовать списки erlang: функция карты

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

Спасибо.

также, я не знаю правильного синтаксиса при использовании этой функции. Например, у меня есть параметр dummy(), который принимает 1 параметр. Я получаю сообщение об ошибке, пытаясь найти время для фиктивной функции.

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

вышеуказанное оценило бы незаконное выражение.

На самом деле, теперь с правильным синтаксисом, функция может быть вызвана правильно с:

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

Однако, он будет бросать исключение, говоря вызывая фиктивную функцию без прохождения какого-либо параметра. Я думаю, что эта линия - злодей, [ G() || _ <- NN ], Я понятия не имею, как это исправить.

+1

Что причина 'G = fun() -> F(), ok end' вместо прямого вызова' F() 'NN раз? – Zed

+0

Моя первоначальная догадка заключалась в том, что это была ошибочная оптимизация, чтобы «выбросить» выход F(), в случае, если накопить его в понимании списка, это замедлило ситуацию. Поэтому я попробовал, и это имеет значение! Если ваш F выдает что-то вроде списка из 255 целых чисел, то выполнение его достаточно времени медленнее в понимании списка, чем вызов G(). Возможно, это связано с накладными расходами на создание списка. Использование списков: foreach - лучшее решение - это намного быстрее, чем понимание списка, и нет необходимости встраивать функцию. –

ответ

6

map используется здесь для выполнения функции

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

для каждого элемента MM. map вернет новый список того же размера, где каждый элемент нового списка является результатом применения вышеуказанной функции к соответствующему элементу MM.

Вы можете вызвать time_it как:

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

С этим:

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

имеет смысла, в настоящее время?

1

Если у вас есть функция MODULENAME: фиктивный/1 вы можете сделать одно из следующих действий

  1. Если вы можете редактировать time_it/3, а затем сделать его называют F(constant_parameter) вместо F(). Я предполагаю, что это так.
  2. В противном случае позвоните по телефону M1:time_it(fun() -> M2:dummy(constant_parameter) end, N, M). Манекен не будет вызываться напрямую, а только F внутри time_it.
4

Цель lists:map в функции time_it - это просто запустить внутреннюю функцию М раз. Когда вы видите эту модель:

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

Это просто означает, что называют Foo() снова и снова М раз, и возвращать результаты каждого вызова в списке. Он фактически составляет список целых чисел [1,2,3,...N] и затем вызывает Foo() один раз для каждого члена списка.
Автор time_it делает этот же трюк снова, потому что time_it необходимо вызвать функцию, которую вы даете ей N * М раз.Таким образом, внутри внешнего контура, которая проходит М раз они используют другой метод, чтобы запустить внутреннюю петлю N раз:

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

Это имеет точно такой же результат, как и приведенный выше код, но на этот раз Foo называется N раз.

Причина у вас возникли проблемы с использованием time_it с фиктивной функцией является то, что time_it принимает функцию с 0 параметров, а не 1. Так что вам нужно сделать фиктивную функцию и называть его так:

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

measure_dummy() -> 
    time_it(fun someModule:dummy/0, 10, 100). 
Смежные вопросы