erlang的性能工具

时间:2013-05-26 21:26:44

标签: optimization functional-programming erlang continuation-passing

编写像factorial这样的函数时:

fac(Val) when is_integer(Val)->
    Visit = fun (X, _F) when X < 2 -> 
                    1;
                (X, F) ->
                    X * F(X -1, F)
            end,
    Visit(Val, Visit).

人们不禁注意到尾部调用优化并不是直接的,但是以连续解析风格编写它是:

fac_cps(Val) when is_integer(Val)->
    Visit = fun (X, _F, K) when X < 2 -> 
                    K (1);
                (X, F, K) ->
                    F(X-1, F, fun (Y) -> K(X * Y) end)
            end,
    Visit(Val, Visit, fun (X) -> X end).

或者甚至可能是功能化的:

fac_cps_def_lambdas({lam0}, X) ->
    X;
fac_cps_def_lambdas({lam1, X, K}, Y) ->
    fac_cps_def_lambdas(K, X*Y).


fac_cps_def(X) when is_integer(X) ->
    fac_cps_def(X, {lam0}).

fac_cps_def(X, K) when X < 2 -> 
    fac_cps_def_lambdas(K,1);
fac_cps_def(X, K) ->
    fac_cps_def(X-1, {lam1, X, K}).

对这三个实现进行定时我发现执行时间和预期的一样。

我的问题是,有没有办法获得比这更详细的知识? 例如,我如何获取执行函数的内存使用情况 - 我是否完全避免任何堆栈内存?

检查这些东西的标准工具是什么?

问题又是如何,我如何确定函数的堆栈高度,如何确定函数调用的内存使用情况,最后哪一个最好?

2 个答案:

答案 0 :(得分:3)

我的解决方案是用眼睛检查代码。随着时间的推移,您将学会发现代码是否采用尾调用方式。通常,我不太关心它,除非我知道通过该代码的结构的大小是巨大的。

这只是凭直觉对我而言。您可以使用erlang:process_info/2检查进程的堆栈大小。您可以使用fprof检查运行时。但我只把它作为最后的手段来解决。

答案 1 :(得分:2)

这不能回答你的问题,但你为什么要编写这样的代码呢?它不是非常Erlangy。除非有特定原因,否则通常不使用明确的CPS,通常不需要。

正如@IGIVECRAPANSWERS所说,你很快就会学会看到尾部调用,并且很少有你真正必须使用它的情况。

编辑:对评论发表评论。没有没有直接的方法来检查编译器是否使用了LCO。它完全符合您的要求,并假设您知道自己在做什么,以及为什么。 :-)但是,你可以肯定它确实可以,但它是关于它的。检查的唯一方法是查看进程的堆栈大小,以查看它是否正在增长。不幸的是,如果你在正确的地方弄错了,那么这个过程会非常缓慢地增长,除了很长一段时间之外很难被发现。

但是,很少有地方你真的需要让LCO正确。

P.S。您使用术语LCO(最后呼叫优化),这是我在以后学到的方法。然而,现在,“他们”似乎使用TCO(尾调用优化)。那是进步。 : - )