我试图并行化一个函数,但我似乎遇到了问题(在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>],[]}]}
答案 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,
这将首先将[]
分配给FirstHalf
和SecondHalf
变量,然后尝试将其与到达的第一条消息相匹配,因为Erlang中的变量无法重新生成分配即可。第二条消息被忽略,因为收到的消息只使用一次。第一个结果可能不是一个空列表,因此它会因badmatch
错误而失败。相反,它似乎意味着执行合并的并行执行,然后收集结果。你可以写:
FirstHalf = receive {Pid1, Msg1} -> Msg1 end,
SecondHalf = receive {Pid2, Msg2} -> Msg2 end,
这将收集上半场,然后收集下半场。
(1)实际上,合格的电话实际上可以由另一个模块执行,或者更准确地说是模块的更新版本。在同一模块中限定调用(循环)函数是在代码升级期间在较新版本中继续执行的常用方法。