erlang没有共享内存.那么sum函数会发生什么呢?

eri*_*icj 0 erlang

Erlang没有共享内存.看一下sum函数,

sum(H|T)->H+sum(T);
sum([])->0
Run Code Online (Sandbox Code Playgroud)

因此sum([1,2,3])= 1 + 2 + 3 + 0

现在发生了什么?erlang是否创建了一个[1,1 + 2,1 + 2 + 3,1 + 2 + 3 + 0]的数组?

7st*_*tud 7

这是发生的事情:

sum([1,2,3]) = 1 + sum([2,3])
                      => sum[2, 3] =  2 + sum([3])
                                             => sum([3]) = 3 + sum([])
                                                                 => sum([]) = 0
Run Code Online (Sandbox Code Playgroud)

现在sum([3])可以评估:

  sum([3]) = 3 + sum([]) = 3 + 0 = 3
Run Code Online (Sandbox Code Playgroud)

这意味着sum([2, 3])可以评估:

sum([2, 3]) = 2 + sum([3]) = 2 + 3 = 5
Run Code Online (Sandbox Code Playgroud)

这意味着sum([1, 2, 3])可以评估:

sum([1,2,3]) = 1 + sum([2,3]) = 1 + 5 = 6
Run Code Online (Sandbox Code Playgroud)

回复评论:

好吧,我想你真正问的是什么immutable variables.假设您有以下C代码:

int x = 0;
x += 1;
Run Code Online (Sandbox Code Playgroud)

该代码是否以某种方式展示shared memory?如果没有,那么C不会对int变量使用共享内存......也不会使用erlang.

在C中你引入一个变量sum,给它一个初始值0,然后你给它添加值.Erlang没有这样做.Erlang做什么?

Erlang为每个递归函数调用在堆栈上分配一个新帧.每个帧存储局部变量及其值,例如参数变量,用于该特定函数调用.堆栈中可以存在多个帧,每个帧存储一个名为X的变量,但它们是单独的变量,因此没有任何X变量被突变 - 而是为每个新帧创建一个新的X变量,并给出新的X.一个新的价值.

现在,如果堆栈在erlang中真的像那样工作,那么执行数百万次的递归函数会向堆栈添加数百万个帧,并且在此过程中可能会耗尽其分配的内存并使程序崩溃.为了避免使用过多的内存,erlang使用了它tail call optimization,它允许函数使用的内存量保持不变.尾调用优化允许erlang用相同大小的后续帧替换堆栈中的第一帧,这使内存使用保持不变.此外,即使函数没有以尾递归格式定义,如sum()函数,erlang也可以优化代码,使其使用恒定的内存(参见Erlang性能七个神话).

在您的sum()函数中,没有变量变异且没有共享内存.但实际上,函数参数变量确实像可变变量一样起作用.

我上面的第一个图表是堆栈的表示,为每个递归函数调用添加一个新帧.如果你重新定义sum()为尾递归,像这样:

sum(List)-> 
    sum(List, 0).

sum([H|T], Total) ->
    sum(T, Total+H);
sum([], Total)->
    Total.
Run Code Online (Sandbox Code Playgroud)

接下来是一个递归函数执行图,表示在堆栈上被替换的帧以保持内存使用量不变:

sum([1, 2, 3]) => sum([1, 2, 3], 0)  [H=1, T=[2,3], Total=0]
               => sum([2,3], 1)      [H=2, T=[3], Total=1]
               => sum([3], 3])       [H=3, T=[], Total=3]
               => sum([], 6)         [Total=6]
=> 6
Run Code Online (Sandbox Code Playgroud)