使用Erlang查找具有K个进程的列表中的最大元素?

使用Erlang查找具有K个进程的列表中的最大元素?,erlang,Erlang,使用单个进程实现算法很容易,但是,如何使用多个进程来完成这项工作 以下是我迄今为止所做的工作 find_largest([H], _) -> H; find_largest([H, Q | T], R) -> if H > Q -> find_largest([H | T], [Q | R]); true -> find_largest([Q | T], [H | R]) end. 感谢您考虑到Erlang如何表示列表,这可能不是一个

使用单个进程实现算法很容易,但是,如何使用多个进程来完成这项工作

以下是我迄今为止所做的工作

 find_largest([H], _) -> H;
 find_largest([H, Q | T], R) ->
     if H > Q -> find_largest([H | T], [Q | R]);
       true -> find_largest([Q | T], [H | R])
 end.

感谢您考虑到Erlang如何表示列表,这可能不是一个并行尝试的好主意。对列表进行分区意味着大量复制(因为它们是链表),将这些分区发送到其他进程也是如此。我认为这种比较比复制所有内容两次,然后合并结果要便宜得多

实现也不正确,您可以在lists.erl中找到一个好的实现作为max/1

%% max(L) -> returns the maximum element of the list L

-spec max([T,...]) -> T.

max([H|T]) -> max(T, H).

max([H|T], Max) when H > Max -> max(T, H);
max([_|T], Max)              -> max(T, Max);
max([],    Max)              -> Max.

如果您的数据已经在不同的进程中,只需获取列表:max/1或每个列表并将其发送到单个位置,然后获取结果列表的列表:max/1。您还可以在收到结果时进行比较,以避免生成此中间列表。

代码的单进程版本应替换为
列表:max/1
。并行化代码的一个有用函数如下所示:

pmap(Fun, List) ->
    Parent = self(),
    P = fun(Elem) ->
            Ref = make_ref(),
            spawn_link(fun() -> Parent ! {Ref, Fun(Elem)} end),
            Ref
        end,
    Refs = [P(Elem) || Elem <- List],
    lists:map(fun(Ref) -> receive {Ref, Elem} -> Elem end end, Refs).
pmap(乐趣,列表)->
Parent=self(),
P=乐趣(要素)->
Ref=make_Ref(),
生成链接(fun()->Parent!{Ref,fun(Elem)}end),
裁判
完,,
Refs=[P(Elem)| | Elem receive{Ref,Elem}->Elem end,Refs)。
pmap/2
Fun
并行应用于
List
的每个成员,并按输入顺序收集结果。若要使用pmap解决此问题,您需要将原始列表分割为列表列表列表并将其传递给pmap。例如
List:max(pmap(Fun List:max/1,ListOfLists))
。当然,对列表进行分段比简单地调用
list:max/1
要昂贵,因此此解决方案需要对列表进行预分段。即使如此,复制列表的开销也可能超过并行化的任何好处,尤其是在单个节点上

这种情况的固有问题是,与管理数据的开销相比,每个子任务的计算量都很小。计算量更大的任务(例如,分解一个大数字列表)更容易并行化


这并不是说找一个最大值不能并行化,但我相信这需要对数据进行预分段或分段,而不需要迭代每个值。

我很难相信pmap对并行化“任何代码”有用,因为它在这种情况下肯定不起作用。就映射/缩减模型而言,pmap只能实现映射阶段,而不能实现缩减阶段。您回答的问题是一个缩减,而不是映射,因此pmap示例充其量是令人困惑的。我同意这是令人困惑的。我编辑了我的原始答案,以解释如何在这种情况下使用pmap为什么它不可能产生一个有用的并行化。谢谢你的反馈!没有试图证明他的代码(甚至运行它),直觉上,它对我来说似乎是正确的,尽管有点模糊。请证明我错了。现在来看,一年多之后,我现在看到的版本似乎确实返回了非空列表的正确答案。它仍然分配了大约2N个不需要存在的列表(其中N个甚至没有被使用!)。是的,它不是很有效,但应该会产生正确的结果。似乎第二个参数是不必要的。您可以完全删除它,而不会丢失功能。