Erlang进程消息接收

时间:2016-04-18 01:50:24

标签: parallel-processing erlang

我正在使用Erlang进行并行计算培训。我有以下代码,计算pi编号:

start(To)->
    Self = self(),
    Cores = erlang:system_info(schedulers_online),
    {Step, Delta} = {1/To, round(To / Cores)},
    Pids = lists:map(fun (El) ->
        spawn(fun()->
            Self ! {sum, calculate(from(El, Delta), to(El, Delta), Step)}
        end)
    end, lists:seq(1, Cores)),
    lists:sum([receive {sum, S} -> S end || _ <- Pids ]) * Step.

现在,它对我来说很神奇

lists:sum([receive {sum, S} -> S end || _ <- Pids ])

请解释这个魔法是如何运作的?

1 个答案:

答案 0 :(得分:2)

lists:sum([receive {sum, S} -> S end || _ <- Pids ])

让我们逐个部分,首先是函数sum,它只是对列表中的所有元素求和,即:

1> lists:sum([1, 2, 3]).
6

lists:sum(SomeList) * Step.只会在 SomeList 的元素总和与 Step 中的值之间进行乘法运算。

有趣的部分是如何构建列表,它是由代码构建的:

[receive {sum, S} -> S end || _ <- Pids ]

你所拥有的是List ComprehensionPids是一个Erlang列表,其中包含您为处理pi编号而创建的每个进程的进程ID(PID):

Pids = lists:map(fun (El) ->
    spawn(fun()->
        Self ! {sum, calculate(from(El, Delta), to(El, Delta), Step)}
    end)
end, lists:seq(1, Cores)).

所以假设你有4个核心,该函数将创建4个进程,可能有一个像[<0.36.0>, <0.38.0>, <0.40.0>, <0.42.0>]这样的列表,主要的重要思想是,如果你有4个核心,你将创建4个进程,如果你有8个核心,8个进程,等等。

每个进程都会调用函数calculate并将结果发送到Self作为消息,您可以在此处看到:

Self ! {sum, calculate(from(El, Delta), to(El, Delta), Step)}

因此,如果您有4个元素,您可以尝试执行以下操作:

6> [X || X <- [1, 2, 3, 4]].
[1,2,3,4]

在那里,您正在使用列表的每个元素构建列表压缩。现在,假设您不关心用于构建新列表的列表元素,您可以执行以下操作:

7> [1 || _ <- [1, 2, 3, 4]].
[1,1,1,1]

并且您将使用列表压缩作为for bucle,您并不真正关心用于构建新列表的列表元素,正是这种情况,您正在执行以下操作:

[1 || _ <- Pids ]

您并不关心Pids的内容是什么,您对列表Pids所包含的元素数量感兴趣。

因此,如果列表Pids有4个元素,您将执行四次接收函数:

receive 
    {sum, S} -> 
        S 
end

该接收函数将侦听发送给进程的任何消息,其模式{sum, S}与您使用{sum, calculate(from(El, Delta), to(El, Delta), Step)}发送的模式相同。函数的返回值为S,在这种情况下,它将是calculate(from(El, Delta), to(El, Delta), Step)的结果。

最后,您将得到一个包含4个元素的列表(同样,假设您有4个核心),其结果由您开始的四个进程计算。