进程<proc_num>中的错误,退出值为:</proc_num>

时间:2014-07-18 22:27:19

标签: parallel-processing erlang

我试图并行化一个函数,但我似乎遇到了问题(在Erlang中)。

我的代码类似于:

-module(examples).
-import(lists, [sublist/2, sublist/3]).

motherFunc(Ls) -> childFunc(Ls, false).

childFunc(Ls, false) ->
    Pid1 = spawn(example, mergesortP, [lists:sublist(Ls, length(Ls) div 2, self()]),
    Pid2 = spawn(example, mergesortP, [lists:sublist(Ls, length(Ls) div 2, self()]),
    FirstHalf = [],
    SecondHalf = [],
    receive
        {Pid1, Msg} -> FirstHalf = Msg;
        {Pid2, Msg} -> SecondHalf = Msg
end,
SecondHalf ++ FirstHalf;
childFunc([], Pid) -> Pid ! {self(), []};
childFunc([L], Pid) -> Pid ! {self(), [L]};
childFunc(Ls, Pid) -> 
    Pid1 = spawn(examples, childFunc, [lists:sublist(Ls, length(Ls) div 2, self()]),
    Pid2 = spawn(examples, childFunc, [lists:sublist(Ls, length(Ls) div 2 + 1, length(Ls) div 2 + 1), self()]),
    FirstHalf = [],
    SecondHalf = [],
    receive
        {Pid1, Msg} -> FirstHalf = Msg;
        {Pid2, Msg} -> SecondHalf = Msg
    end,
    Pid ! {self(), SecondHalf ++ FirstHalf}.

当我运行这个时,我收到两个线程的错误消息,然后它什么都不做:Error in process <0.31.0> with exit value: {undef,[{examples,childFunc,[[1,2,3,4],<0.2.0>],[]}]}

1 个答案:

答案 0 :(得分:2)

函数spawn/3以模块和函数名作为第一个和第二个参数,需要导出函数。

事实上,任何明确的合格电话:

module:function(...)

或隐式合格的电话:

apply(module, function, ...)

要求导出该功能。它是否来自同一模块是无关紧要的(1)。

在您的代码中,您应该使用spawn/1或导出函数:

-export([childFunc/2, mergesortP/2]).

% ...

spawn(?MODULE, mergesortP, [lists:sublist(Ls, length(Ls) div 2), self()])

Self = self(),
spawn(fun() -> mergesortP(lists:sublist(Ls, length(Ls) div 2), Self) end.

注意传递self()时的差异。通过spawn/3调用,self()由产生过程评估,因此是它的pid。如果您在传递给self()的匿名函数中调用spawn/1,它将评估生成进程的pid。因此,您需要先调用它并将其传递给变量。

此外,您的代码不太可能正常工作。实际上,以下部分并不是您的意思:

FirstHalf = [],
SecondHalf = [],
receive
    {Pid1, Msg} -> FirstHalf = Msg;
    {Pid2, Msg} -> SecondHalf = Msg
end,

这将首先将[]分配给FirstHalfSecondHalf变量,然后尝试将其与到达的第一条消息相匹配,因为Erlang中的变量无法重新生成分配即可。第二条消息被忽略,因为收到的消息只使用一次。第一个结果可能不是一个空列表,因此它会因badmatch错误而失败。相反,它似乎意味着执行合并的并行执行,然后收集结果。你可以写:

FirstHalf = receive {Pid1, Msg1} -> Msg1 end,
SecondHalf = receive {Pid2, Msg2} -> Msg2 end, 

这将收集上半场,然后收集下半场。


(1)实际上,合格的电话实际上可以由另一个模块执行,或者更准确地说是模块的更新版本。在同一模块中限定调用(循环)函数是在代码升级期间在较新版本中继续执行的常用方法。