要实现一个函数,参数是一个list,结果是将list里每个数字都+1,返回一个新的list,会怎么实现呢?
看代码,哪个函数性能最好?(除了add2,因为他的结果是不正确的)
-module(t). -compile(export_all). add1([]) -> []; add1([H|T]) -> [H+1|add1(T)]. add2(R) -> add(R,[]). add3(R) -> lists:reverse(add(R,[])). add4([]) -> []; add4(L) -> lists:map(fun(X) -> X+1 end,L). add([],R) -> R; add([H|T],R) -> add(T,[H+1|R]). t(N) -> L = lists:seq(1,N), {T1,_}=timer:tc(a,add1,[L]), {T2,_}=timer:tc(a,add2,[L]), {T3,_}=timer:tc(a,add3,[L]), {T4,_}=timer:tc(a,add4,[L]), io:format("~p ~p ~p ~p ~n",[T1,T2,T3,T4]).
函数说明:
*add1 是最简单的实现,没有使用尾递归
*add2 使用尾递归,最后没有reverse,结果是不正确的,仅仅用来比较
*add3 使用尾递归
*add4 使用list comprehension
在我的笔记本上运行,在N比较小(N<100000)的情况下,add3几乎总是比add1快,但是N比较大(N>100000)的时候,add1经常比add3快,说明lists:reverse的消耗还是挺大的
这个场景说明了几个问题:
*在list比较大的时候,reverse操作消耗还是很大的(废话)
*erlang的编译器会对类似add1的情况做优化,如果没有优化的话,应该会死的很惨
*当使用尾递归会带来额外的事情的时候,需要权衡一下,是否应该选用
*如果能事先知道程序运行的场景(这里是N的大小),写出来的程序性能才能更好
似乎都是废话,仅当记录。