2009-10-10 85 views
9

以下是erlang函数。我不明白在这里如何使用list:map函数。 有人能解释一下吗?如何使用erlang列表:map函数

% 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

如果你有一个功能模块名:假/ 1,你可以做以下

  1. 一个如果你可以编辑time_it/3,然后使它调用F(constant_parameter)代替F()。我认为是这样。
  2. 否则,请致电M1:time_it(fun() -> M2:dummy(constant_parameter) end, N, M)。 不会直接调用dummy,而只能通过time_it中的F来调用。
4

lists:maptime_it函数中的作用就是运行内部函数M次。当你看到这个模式:

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

这只是意味着一次次给Foo() M次,并以列表返回每次调用的结果。它实际上会生成一个整数列表[1,2,3,...N],然后为列表中的每个成员调用Foo()一次。
time_it的作者又这样做了,因为time_it需要调用你给它N * M次的函数。这样运行的M倍的外循环内他们使用不同的技术来运行内环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).