【问题标题】:Erlang: parallel accumulatorErlang:并行累加器
【发布时间】:2019-07-29 05:11:06
【问题描述】:

我正在研究一种用于执行累加器并行化版本的 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>},

我一直在尝试以与合并排序或其他分而治之算法类似的方式来处理此问题,但我不知道从这一点开始应该在哪里修改代码。

【问题讨论】:

    标签: parallel-processing erlang pid


    【解决方案1】:

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

    Pl = spawn(fun() -> reduceFunc(Pids, L) end),
    Pr = spawn(fun() -> reduceFunc(Pids, R) end)
    
    1. 您定义的函数 reduceFunc/2 的第一个参数是 FUNC,但您输入了 PID(在您的示例中为 ),所以您的机器转储错误。

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

    【讨论】:

      【解决方案2】:

      所以,我想出了一种方法来回答这个问题。

      我必须并行化我编写的串行程序以提高效率。

      在下面的例子中:

      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.
      

      【讨论】:

      • 嗨 reverb1010,欢迎来到 Stack Overflow!您能否在答案中再描述一下您的代码示例?谢谢!
      • 是的,所以基本上这是一个编码项目,我正在致力于并行化我编写的串行程序以提高效率。在上面的代码中,我的想法是 1.) 将列表分成两半; 2.) 将两半发送给其他进程同时处理 3) 等待它们返回; 4) 对两半应用适当的归约操作。
      • 谢谢!我已将您的评论编辑到您的答案中,以使提问者以及以后发现此问题的任何其他人都清楚。
      猜你喜欢
      • 2018-09-27
      • 1970-01-01
      • 2014-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-07
      • 1970-01-01
      • 2021-05-31
      相关资源
      最近更新 更多