我正在研究如何编码" map reduce"直接在erlang中输入方案。作为一个玩具示例,想象一下我想确定哪个文件最大。这些文件可能在互联网上的任何地方,因此获取每个文件可能需要一些时间;所以我想并行收集它们。一旦我拥有它们,我就可以比较它们的尺寸。
我假设的方法如下:
这是一个笨重但功能正常的示例(仅使用本地文件,但它显示了意图):
-module(cmp).
-export([cmp/2]).
cmp(Fname1, Fname2) ->
Pid1 = fsize(Fname1),
Pid2 = fsize(Fname2),
{Size1, Size2} = collect(Pid1, Pid2),
if
Size1 > Size2 ->
io:format("The first file is bigger~n");
Size2 > Size1 ->
io:format("The second file is bigger~n");
true ->
io:format("The files are the same size~n")
end.
fsize(Fname) ->
Pid = spawn(?MODULE, fsize, [self(), Fname]),
Pid.
fsize(Sender, Fname) ->
Size = filelib:file_size(Fname),
Sender ! {self(), Fname, Size}.
collect(Pid1, Pid2) ->
receive
{Pida, Fnamea, Sizea} ->
io:format("Pid: ~p, Fname: ~p, Size: ~p~n", [Pida, Fnamea, Sizea])
end,
receive
{Pidb, Fnameb, Sizeb} ->
io:format("Pid: ~p, Fname: ~p, Size: ~p~n", [Pidb, Fnameb, Sizeb])
end,
if
Pida =:= Pid1 -> {Sizea, Sizeb};
Pida =:= Pid2 -> {Sizeb, Sizea}
end.
具体问题
collect
函数是什么?感谢。
-
注意:我知道collect
函数特别笨重;它可以通过例如推广来概括将pid存储在列表中,并循环直到所有已完成。
答案 0 :(得分:2)
在我看来,最好从一个例子中学习,所以我看看他们是如何在otp/rpc
中做到这一点的,并在此基础上我实现了parallel eval call的更短/更简单的版本。
call(M, F, ArgL, Timeout) ->
ReplyTo = self(),
Keys = [spawn(fun() -> ReplyTo ! {self(), promise_reply, M:F(A)} end) || A <- ArgL],
Yield = fun(Key) ->
receive
{Key, promise_reply, {error, _R} = E} -> E;
{Key, promise_reply, {'EXIT', {error, _R} = E}} -> E;
{Key, promise_reply, {'EXIT', R}} -> {error, R};
{Key, promise_reply, R} -> R
after Timeout -> {error, timeout}
end
end,
[Yield(Key) || Key <- Keys].
答案 1 :(得分:1)
我不是MapReduce专家,但我确实有使用this 3rd party mapreduce module的经验。所以我会根据我目前的知识来回答你的问题。
{K1,V1}
。然后,它使用键和值执行 map 函数,并发出一对新的键和值 {K2,V2}
。 主进程收集结果并等待所有工作人员完成其工作。完成所有工作后,主服务器启动工作人员发出的对{K2,List[V2]}
上的 reduce 部分。这部分可以并行执行或不执行,它用于将所有结果组合成单个输出。请注意,List[V2]
是因为工作人员针对单个K2
密钥发出的值可能超过一个。从我上面提到的第三方模块:
%% Input = [{K1, V1}]
%% Map(K1, V1, Emit) -> Emit a stream of {K2,V2} tuples
%% Reduce(K2, List[V2], Emit) -> Emit a stream of {K2,V2} tuples
%% Returns a Map[K2,List[V2]]
如果我们研究Erlangs&#39; lists函数, map 部分实际上与执行lists:map/2
相等,而reduce部分在某种程度上类似于lists:foldl/3
或lists:foldr/3
它们之间的组合是:lists:mapfoldl/3
,lists:mapfoldr/3
。
我建议你回顾我上面提到的第三方模块。另请参阅this example。如您所见,您需要定义的唯一内容是Map
和Reduce
函数。