Optimization erlang的性能工具

Optimization erlang的性能工具,optimization,functional-programming,erlang,continuation-passing,Optimization,Functional Programming,Erlang,Continuation Passing,编写类似阶乘的函数时: 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(Val)何时为_整数(Val)-> 当X 1. (X

编写类似阶乘的函数时:

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(Val)何时为_整数(Val)->
当X<2->
1.
(X,F)->
X*F(X-1,F)
完,,
拜访(瓦尔,拜访)。
人们不禁会注意到,尾部调用优化并不是直截了当的,但以延续解析风格编写它是:

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\u cps(Val)何时为整数值(Val)->
当X<2->
K(1);
(X,F,K)->
F(X-1,F,fun(Y)->K(X*Y)结束)
完,,
参观(Val、参观、娱乐(X)->X结束)。
或者甚至可能失效:

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}).
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)何时为_整数(X)->
fac_cps_def(X,{lam0})。
当X<2->
fac_cps_def_lambdas(K,1);
fac_cps_def(X,K)->
fac_cps_def(X-1,{lam1,X,K})。
对这三种实现进行计时,我发现执行时间与预期的一样

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

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


问题是,如何测量函数的堆栈高度,如何确定每个函数调用的内存使用率,最后,哪一个是最好的?

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


对我来说,这只是直觉。您可以使用
erlang:process\u info/2
检查进程的堆栈大小。您可以使用
fprof
检查运行时。但我只是在万不得已的情况下才这么做。

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


对我来说,这只是直觉。您可以使用
erlang:process\u info/2
检查进程的堆栈大小。您可以使用
fprof
检查运行时。但我只是在万不得已的情况下才这么做。

这并不能回答您的问题,但为什么要这样编写代码呢?这不是很好。通常不使用显式CPS,除非有特定原因,通常不需要

正如@IGIVECRAPANSWERS所说,你很快就会学会看到尾部呼叫,而且很少有情况下你必须使用它

编辑:注释的注释。不,没有直接的方法来检查编译器是否使用了LCO。它完全按照你告诉它的去做,并且假设你知道你在做什么,以及为什么。:-)然而,你可以肯定,当它可以,但它是关于它。检查的唯一方法是查看进程的堆栈大小,看看它是否在增长。不幸的是,如果你在正确的地方弄错了,这个过程可能会发展得非常缓慢,除非经过很长一段时间,否则很难被发现

但同样,很少有地方真正需要让LCO做出正确的决定


另外,您使用的术语是LCO(最后一次呼叫优化),这是我很久以前学到的。然而,现在,“他们”似乎改用TCO(尾部呼叫优化)。这就是进步。:-)

这并不能回答您的问题,但您为什么要这样编写代码?这不是很好。通常不使用显式CPS,除非有特定原因,通常不需要

正如@IGIVECRAPANSWERS所说,你很快就会学会看到尾部呼叫,而且很少有情况下你必须使用它

编辑:注释的注释。不,没有直接的方法来检查编译器是否使用了LCO。它完全按照你告诉它的去做,并且假设你知道你在做什么,以及为什么。:-)然而,你可以肯定,当它可以,但它是关于它。检查的唯一方法是查看进程的堆栈大小,看看它是否在增长。不幸的是,如果你在正确的地方弄错了,这个过程可能会发展得非常缓慢,除非经过很长一段时间,否则很难被发现

但同样,很少有地方真正需要让LCO做出正确的决定


另外,您使用的术语是LCO(最后一次呼叫优化),这是我很久以前学到的。然而,现在,“他们”似乎改用TCO(尾部呼叫优化)。这就是进步。:-)

你的权利我的代码不是很erlangy,我开始我的函数编程天做sML。然而,问题仍然是一样的。主要是有没有一种方法可以检查是否检测到LCO?顺便说一句,我从Olivier Danvy教授那里学到了“最后一次呼叫优化”这个术语,他是科学界被引用最多的人,我不会因为某些原因而改变它。:-)你的权利我的代码不是很erlangy,我开始我的函数编程天做sML。然而,问题仍然是一样的。主要是有没有一种方法可以检查是否检测到LCO?顺便说一句,我从Olivier Danvy教授那里学到了“最后一次呼叫优化”这个术语,他是科学界被引用最多的人,我不会因为某些原因而改变它。:-)我感兴趣的一件事是,在没有我询问的情况下,erlang做了多少LCO工作,以及什么时候自己做才有意义——我只是想检查一下。我知道最后一个版本会被优化,但是第一个版本呢,
X*F(X-1,F)
是否意味着我们会得到一堆X,然后在堆栈中相乘?不,Olivier可能会