列表理解和列表之间的效果:map / 2,后者的性能似乎比我的测试更好。
参考效率指南中关于列表理解的参考链接 用户指南:http://www.erlang.org/doc/efficiency_guide/listHandling.html#id66810
它说" 如果显然不会使用列表理解的结果,则不会构建列表。"
问题:我想知道列表:map / 2' s结果如何不使用(比如list:foreach / 2),它是否与列表理解相同& #34;不会构建列表" ??
答案 0 :(得分:2)
检查这一点的一种方法是编写一个以明显无用的方式使用lists:map/2
的函数,然后跟踪它。考虑这个功能:
map() ->
dbg:tracer(), dbg:p(self(), call),
dbg:tpl(lists,map,c),
lists:map(fun(X) -> X end, []),
dbg:stop_clear().
如果你在模块x
中实现这个功能,编译它,然后在shell中产生一个对它的调用(spawn消除了shell本身引起的跟踪消息),你会看到如下内容:
3> spawn(x,map,[]).
<0.45.0>
(<0.45.0>) call lists:map(#Fun<dbg.2.121426812>,[]) ({lists,map,2})
(<0.45.0>) call lists:map(#Fun<x.0.133743400>,[]) ({x,map,0})
(<0.45.0>) call lists:map(#Fun<dbg.2.121426812>,[nonode@nohost]) ({dbg,
do_ctp,2})
(<0.45.0>) call lists:map(#Fun<dbg.2.121426812>,[]) ({lists,map,2})
(<0.45.0>) call lists:map(#Fun<dbg.2.121426812>,[nonode@nohost]) ({dbg,
do_ctp,2})
从跟踪输出的第三行可以看出,调用了匿名函数#Fun<x.0.133743400>
,这是我们x:map/0
函数中的匿名函数,调用者是{x,map,0}
,更好地称为x:map/0
。 (所有其他跟踪消息都是由我用于跟踪的dbg
模块的调用引起的。)
另一种方法是使用-S
编译器的erlc
选项编译到程序集。首先取消dbg
来电:
map() ->
lists:map(fun(X) -> X end, []).
然后使用-S
进行编译并查看结果:
{function, map, 0, 4}.
{label,3}.
{line,[{location,"x.erl",8}]}.
{func_info,{atom,x},{atom,map},0}.
{label,4}.
{make_fun2,{f,15},0,0,0}.
{move,nil,{x,1}}.
{line,[{location,"x.erl",9}]}.
{call_ext_only,2,{extfunc,lists,map,2}}.
这里的重要行是最后一个,{move,nil,{x,1}}.
,它将空列表移动到VM寄存器中作为参数传递,最后一行是lists:map/2
的调用
根据使用Erlang 17.4构建的这些结果,可以肯定地说你问题的答案是否定的。
答案 1 :(得分:1)
lists:map/2
是一个已经在你的系统中编译过的函数,实际上要点是它是在一个单独的模块中编译的,你的代码,所以编译器不能生成关于结果的使用与否的任何假设。 list comprehension在您的代码中编译,因此可以执行优化
[编辑] 抱歉,我没有重新检查,列表:地图已写:
map(F, [H|T]) ->
[F(H)|map(F, T)];
map(F, []) when is_function(F, 1) -> [].
不是列表理解!