Erlang中的惯用进程同步

Erlang中的惯用进程同步,erlang,Erlang,我正在研究如何直接在erlang中编写“map reduce”类型的场景。作为一个玩具示例,假设我想确定几个文件中哪个文件最大。这些文件可能在互联网上的任何地方,因此获取每个文件可能需要一些时间;所以我想平行地收集它们。一旦我有了它们,我就可以比较它们的大小了 我的假设方法如下: 一个“主要”流程来协调工作并确定哪一个是最大的 每个文件都有一个“worker”进程,它获取文件并将大小返回给主进程 下面是一个笨重但功能正常的示例(仅使用本地文件,但它显示了目的): 具体问题 这种方法是惯用的吗

我正在研究如何直接在erlang中编写“map reduce”类型的场景。作为一个玩具示例,假设我想确定几个文件中哪个文件最大。这些文件可能在互联网上的任何地方,因此获取每个文件可能需要一些时间;所以我想平行地收集它们。一旦我有了它们,我就可以比较它们的大小了

我的假设方法如下:

  • 一个“主要”流程来协调工作并确定哪一个是最大的
  • 每个文件都有一个“worker”进程,它获取文件并将大小返回给主进程
下面是一个笨重但功能正常的示例(仅使用本地文件,但它显示了目的):

具体问题

  • 这种方法是惯用的吗?i、 e.将每个“长时间运行”的任务划分到单独的流程中,然后将结果收集回“主”中
  • 是否有处理同步机制的库?具体来说,上面示例中的
    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]]