Erlang:并行累加器

时间:2018-04-19 02:31:09

标签: parallel-processing erlang pid

我正在研究一种Erlang方法,即执行累加器的并行化版本。该方法是采用关联和可交换运算符以及值列表,然后通过将运算符应用于列表中的值来返回答案。以下两个示例显示了程序的命令行I / O:

示例1

CL Input: sum(fun (A,B) -> A++B end , ["U", "V", "W"]).
CL Output: "UVW"

示例2

CL Input: sum(fun(A,B) -> A+B end, [2,6,7,10,12]
CL Output: 37

这是我到目前为止的代码。我的问题是,如何更改此方法以适应上述示例,以及并行生成正确的结果?

reduceFunc(Func, [Acc]) -> Acc;
    reduceFunc(Func, List) ->
       { L, R } = lists:split(trunc(length(List)/2), List),
        Pids = self(),
        io:format("Distribute processes~n"),
        Pl = spawn(fun() -> reduceFunc(Pids, L) end),
        Pr = spawn(fun() -> reduceFunc(Pids, R) end),
        Func(Pl, Pr).

代码在评估运算符时返回算术表达式错误(例如,+ / 2),然后给出每个的PID而不应用数值和运算符,例如...

Error in process <0.100.0> with exit value:
{{badfun,<0.95.0>},

我一直试图以类似于合并排序或另一种分治算法的方式来解决这个问题,但我不知道从这一点开始修改代码的位置。

2 个答案:

答案 0 :(得分:1)

你有一些错误,我将在下面列出:

Pl = spawn(fun() -> reduceFunc(Pids, L) end),
Pr = spawn(fun() -> reduceFunc(Pids, R) end)
  1. 您定义了函数reduceFunc / 2,第一个arg是 FUNC ,但是您输入了PID(此处为您的示例&lt; 0.95.0&gt;),所以你的机器转储错误。

  2. 您生成了从属进程但未将结果返回到主进程。 spawn函数总是返回从属进程的PID,而不是返回函数的结果。您应该为主进程和从进程定义发送和接收结果。

答案 1 :(得分:1)

所以,我想出了一种答案。

为了使效率更高,我不得不并行编写一个串行程序。

在下面的示例中:

  1. 将列表分成两半;
  2. 将这两个半部分发送给其他进程同时处理;
  3. 等待他们的归来;
  4. 对两半进行适当的归约运算。
    -module(erlang2).
    -compile(export_all).
    -export([reduce/2]).

    reduce(Func, List) ->
        reduce(root, Func, List).

    %When done send results to Parent
    reduce(Parent, _, [A]) -> 
        %send to parent 
        Parent ! { self(), A}; 

    %get contents of list, apply function and store in Parent
    reduce(Parent, Func, List) ->
                { Left, Right } = lists:split(trunc(length(List)/2), List),
                Me = self(),
                %io:format("Splitting in two~n"),
                Pl = spawn(fun() -> reduce(Me, Func, Left) end),
                Pr = spawn(fun() -> reduce(Me, Func, Right) end),
                %merge results in parent and call Func on final left and right halves
                combine(Parent, Func,[Pl, Pr]).

    %merge pl and pl and combine in parent
    combine(Parent, Func, [Pl, Pr]) ->
        %wait for processes to complete (using receive) and then send to Parent
        receive
            { Pl, Sorted } -> combine(Parent, Func, Pr, Sorted);
            { Pr, Sorted } -> combine(Parent, Func, Pl, Sorted)
        end.

    combine(Parent, Func, P, List) ->
        %wait and store in results and then call ! to send
        receive
            { P, Sorted } ->
                Results = Func(Sorted, List),
                case Parent of
                    root ->
                        Results;
                    %send results to parent
                    _ -> Parent ! {self(), Results}
                end
        end.