我们用列表非常大名单:SEQ(1100)创建的列表,包括100元和创造速度是可以接受的如何创建二郎
但是如果我们创建千瓦特元素的列表? 列表:SEQ(1,10000000)是很慢的。
你有什么想法没有任何datacopy创建一个大名单?
我们用列表非常大名单:SEQ(1100)创建的列表,包括100元和创造速度是可以接受的如何创建二郎
但是如果我们创建千瓦特元素的列表? 列表:SEQ(1,10000000)是很慢的。
你有什么想法没有任何datacopy创建一个大名单?
其实,lists:seq/2
不执行任何复制。下面是实际执行:
seq(First, Last)
when is_integer(First), is_integer(Last), First-1 =< Last ->
seq_loop(Last-First+1, Last, []).
seq_loop(N, X, L) when N >= 4 ->
seq_loop(N-4, X-4, [X-3,X-2,X-1,X|L]);
seq_loop(N, X, L) when N >= 2 ->
seq_loop(N-2, X-2, [X-1,X|L]);
seq_loop(1, X, L) ->
[X|L];
seq_loop(0, _, L) ->
L.
所以,递归调用自己,在每个呼叫(第三个参数)添加最多4个元素累加器。将元素预先列入列表不涉及任何复制,并且调用是递归的,因此堆栈具有恒定的大小。
编辑:为了完整起见,我粘贴了一些来自评论的说明: Erlang列表是链接列表。内部[H | T],创建元素H并向T添加指针。T永远不会被复制。你可以这样做,因为T是不可变的,即使你创建了[H1 |也不会改变T],[H2 | T]和[H3 | T] - T是他们之间共享。
与列表作为参数调用函数还没有涉及复制:)包括列表更大的数据结构存储在进程堆。您只存储指向堆栈中第一个元素的指针。只发送消息到另一个进程实际上会复制列表。
创建非常大的名单可能是缓慢的,因为你可以用完物理内存开始使用交换。 END编辑
关于迭代,我想建立在萨科塔尔费尔河的答案 - 有时你想参数传递给函数调用的循环,你可以使用高阶函数和闭包要做到这一点:
main(_) ->
InitialArgs = 6,
InitialFun = fun() -> do_stuff(InitialArgs) end,
Ret = forloop(InitialFun, 5),
io:format("~p", [Ret]).
forloop(Fun, 1) ->
Fun();
forloop(Fun, Count) ->
RetVal = Fun(),
NewFun = fun() -> do_stuff(RetVal) end,
forloop(NewFun, Count-1).
do_stuff(Args) ->
Args + 2.
我假设你要重复的操作N次的independantly列表内容。 我错了吗? 即是这样的:
[ fun() -> do_stuff() end || _X <- lists:seq(1,10000000) ].
考虑这样做,而不是:
foo(0) ->
ok;
foo(Count) ->
do_stuff(),
foo(Count-1).
并调用foo(10000000).
这个工作,但我还是想知道如何创建这样的大单子有效 – CaTFooD 2014-09-11 09:30:23
事实上,你可以尝试使用惰性列表: 它看起来像这样:
seq(M, N) when M =< N ->
fun() -> [M | seq(M+1, N)] end;
seq(_, _) ->
fun() -> [] end.
E = seq(1, 1000000000000000).
[1|NextElem] = E().
[2|NextElem2] = NextElem().
它仍然副本[X-3,X -2,X -1,X | L] :( – CaTFooD 2014-09-11 09:33:24
不,它不。 Erlang列表是链接列表。内部[H | T],创建元素H并向T添加指针。T永远不会被复制。你可以这样做,因为T是不可变的,即使你创建了[H1 |也不会改变T],[H2 | T]和[H3 | T] - T是他们之间共享。 – tkowal 2014-09-11 09:44:31
是,[H3 | T]没有任何复制的东西,但是当你通过这个列表作为参数传递给函数,它复制列表:( – CaTFooD 2014-09-11 10:00:50