Erlang中的惯用进程同步
我正在研究如何直接在erlang中编写“map reduce”类型的场景。作为一个玩具示例,假设我想确定几个文件中哪个文件最大。这些文件可能在互联网上的任何地方,因此获取每个文件可能需要一些时间;所以我想平行地收集它们。一旦我有了它们,我就可以比较它们的大小了 我的假设方法如下:Erlang中的惯用进程同步,erlang,Erlang,我正在研究如何直接在erlang中编写“map reduce”类型的场景。作为一个玩具示例,假设我想确定几个文件中哪个文件最大。这些文件可能在互联网上的任何地方,因此获取每个文件可能需要一些时间;所以我想平行地收集它们。一旦我有了它们,我就可以比较它们的大小了 我的假设方法如下: 一个“主要”流程来协调工作并确定哪一个是最大的 每个文件都有一个“worker”进程,它获取文件并将大小返回给主进程 下面是一个笨重但功能正常的示例(仅使用本地文件,但它显示了目的): 具体问题 这种方法是惯用的吗
- 一个“主要”流程来协调工作并确定哪一个是最大的李>
- 每个文件都有一个“worker”进程,它获取文件并将大小返回给主进程
collect
函数是什么注意:我知道收集功能特别笨重;例如,可以通过将PID存储在列表中,并循环直到全部完成来概括 在我看来,最好从一个示例中学习,因此我了解了他们是如何做到这一点的,并在此基础上实现了一个略短/更简单的版本
调用(M、F、ArgL、超时)->
ReplyTo=self(),
Keys=[spawn(fun()->ReplyTo!{self(),promise_reply,M:F(A)}end)|A
接收
{Key,promise\u reply,{error,{R}=E}->E;
{Key,promise\u reply,{'EXIT',{error,{R}=E}->E;
{Key,promise\u reply,{'EXIT',R}}->{error,R};
{Key,promise\u reply,R}->R
超时后->{错误,超时}
结束
完,,
[Yield(Key)| | Key我不是专家,但我确实有一些使用经验。因此,我将根据我目前的知识尝试回答您的问题
首先,为了正确使用mapreduce模型,您的输入应该被安排为成对的键和值。通常,您的主进程应该首先启动辅助进程(或节点)。每个辅助进程都会收到一个映射函数和一对键和值,让我们将其命名为{K1,V1}
。然后,它使用键和值执行map函数,并发出一对新的键和值{K2,V2}
。主进程收集结果并等待所有工作进程完成其工作。所有工作进程完成后,主进程启动对{K2,List[V2]}上的reduce部分
由工作者发出。此部分可以并行执行,也可以不并行执行,它用于将所有结果合并到单个输出中。请注意,列表[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的函数,map部分实际上等同于执行列表:map/2
,reduce部分在某种程度上类似于列表:foldl/3
或列表:foldr/3
,它们之间的组合是:列表:mapfoldl/3
,列表:mapfoldr/3
如果您使用的是mapreduce的这种模式,使用的是一组键和值,那么如果这是您的意思,那么就不需要进行特殊的同步。您只需要等待所有工作人员完成他们的工作
我建议你浏览一下我上面提到的第三方模块。也看看。正如你所看到的,你只需要定义Map
和Reduce
函数。谢谢-我还没有找到mapreduce模块。这不完全是我要找的,而是一个很好的参考。你可以随时制作自己的mapreduce modu例如,您可以将reduce部分更改为sequential,只需使用某种类型的foldl
。例如,我使用了这个第三方模块。谢谢-一个更优雅的实现,也验证了“许多工作人员”的习惯用法。
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].
%% 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]]