2009-10-10 34 views
9

Sau đây là chức năng xóa. Tôi không hiểu cách danh sách: chức năng bản đồ được sử dụng ở đây. Ai đó có thể giải thích?cách sử dụng danh sách erlang: chức năng bản đồ

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

Cảm ơn.

cũng vậy, tôi không biết cú pháp đúng khi sử dụng chức năng này. Ví dụ, tôi có một hàm dummy() lấy 1 tham số. Tôi gặp lỗi khi cố gắng thời gian chức năng giả.

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

ở trên sẽ đánh giá biểu hiện bất hợp pháp.

Trên thực tế, bây giờ với cú pháp chính xác, các chức năng có thể được gọi một cách chính xác với:

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

Tuy nhiên, nó sẽ ném một ngoại lệ nói cách gọi chức năng giả mà không đi bất kỳ thông số. Tôi nghĩ rằng dòng này là nhân vật phản diện, [ G() || _ <- NN ], Tôi không có ý tưởng làm thế nào để sửa chữa nó.

+1

gì lý do cho 'G = fun() -> F(), ok end' thay vì gọi trực tiếp' F() 'NN lần? – Zed

+0

Đoán ban đầu của tôi là đây là một sự tối ưu hóa sai lầm để "vứt bỏ" đầu ra của F() trong trường hợp bằng cách tích lũy nó trong danh sách hiểu nó làm chậm mọi thứ xuống. Vì vậy, tôi đã thử nó và nó tạo nên sự khác biệt! Nếu F của bạn xuất hiện một cái gì đó giống như một danh sách của 255 số nguyên, sau đó chạy nó đủ thời gian là chậm hơn trong một danh sách hiểu hơn gọi G(). Có lẽ điều này là do chi phí của việc xây dựng danh sách. Sử dụng danh sách: foreach là giải pháp tốt hơn - điều này nhanh hơn nhiều so với việc hiểu danh sách và không cần phải lồng hàm. –

Trả lời

6

map được sử dụng ở đây để thực hiện chức năng

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

cho mỗi phần tử của MM. map sẽ trả về một danh sách mới có cùng kích thước, trong đó mỗi phần tử của danh sách mới là kết quả của việc áp dụng hàm trên cho phần tử tương ứng của MM.

Bạn có thể gọi time_it như:

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

Với những:

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

Make nghĩa nào đó, bây giờ không?

1

Nếu bạn có một hàm môđun: dummy/1 bạn có thể làm một trong các cách sau

  1. Nếu bạn có thể chỉnh sửa time_it/3, sau đó làm cho nó gọi F(constant_parameter) thay vì F(). Tôi cho rằng đây là trường hợp.
  2. Nếu không, hãy gọi M1:time_it(fun() -> M2:dummy(constant_parameter) end, N, M). giả sẽ không được gọi trực tiếp, nhưng chỉ bằng F bên trong time_it.
4

Mục đích của lists:map trong chức năng time_it chỉ để chạy hàm bên trong M lần. Khi bạn thấy mẫu này:

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

Nó chỉ có nghĩa là gọi Foo() một lần nữa và trả lại kết quả của mỗi cuộc gọi trong danh sách. Nó thực sự làm cho một danh sách các số nguyên [1,2,3,...N] và sau đó gọi Foo() một lần cho mỗi thành viên của danh sách.
Tác giả của time_it thực hiện lại thủ thuật tương tự này, bởi vì time_it cần phải gọi hàm mà bạn cung cấp cho nó N * M lần.Vì vậy, bên trong vòng lặp bên ngoài mà chạy M lần họ sử dụng một kỹ thuật khác nhau để chạy các lần lặp N bên trong:

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

này có chính xác kết quả tương tự như đoạn mã trên, nhưng lần này Foo được gọi là N lần.

Lý do bạn đang gặp vấn đề khi dùng time_it với chức năng giả của bạn là time_it mất một chức năng với 0 thông số, chứ không phải 1. Vì vậy, bạn cần phải thực hiện một chức năng dummy và gọi nó là như thế này:

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

measure_dummy() -> 
    time_it(fun someModule:dummy/0, 10, 100). 
Các vấn đề liên quan