Erlang中的并行深度优先搜索比顺序搜索慢

Erlang中的并行深度优先搜索比顺序搜索慢,erlang,parallel-processing,depth-first-search,Erlang,Parallel Processing,Depth First Search,我试图在Erlang中实现一个改进的并行深度优先搜索算法(我们称之为*dfs\u mod*) 我想要得到的是所有的“死胡同”,基本上是当*dfs_mod*访问一个没有邻居的顶点或一个已经访问过邻居的顶点时返回的路径。如果我的自定义函数fun1(path)返回true,我将每个路径保存到ets\u表1,如果fun1(path)返回false(我需要使用一些客户过滤器过滤产生的“死胡同”路径),我将每个路径保存到ets\u表2 我已经实现了这个算法的顺序版本,出于某种奇怪的原因,它的性能比并行算法要

我试图在Erlang中实现一个改进的并行深度优先搜索算法(我们称之为*dfs\u mod*)

我想要得到的是所有的“死胡同”,基本上是当*dfs_mod*访问一个没有邻居的顶点或一个已经访问过邻居的顶点时返回的路径。如果我的自定义函数
fun1(path)
返回
true
,我将每个路径保存到
ets\u表1
,如果
fun1(path)
返回
false
(我需要使用一些客户过滤器过滤产生的“死胡同”路径),我将每个路径保存到
ets\u表2

我已经实现了这个算法的顺序版本,出于某种奇怪的原因,它的性能比并行算法要好

并行实现背后的思想很简单:

  • [顶点|其他_顶点]=未访问的_邻居访问一个
    顶点
  • 将此
    顶点添加到当前路径
    
  • {self(),wait}
    发送到“收集器”进程
  • 新进程中为当前
    顶点的
    未访问的
    邻居运行*dfs\u mod*
    
  • 继续使用提供的其余顶点运行*dfs_mod*(
    其他_顶点
  • 当没有更多顶点可访问时-将
    {self(),done}
    发送到收集器进程并终止
所以,基本上每次我访问一个有未访问邻居的顶点时,我都会产生一个新的深度优先搜索过程,然后继续搜索其他顶点

在生成第一个*dfs_mod*进程之后,我立即开始收集所有
{Pid,wait}
{Pid,done}
消息(
wait
消息是让收集器等待所有
done
消息)。等待后的N毫秒内,收集器函数返回
ok


出于某种原因,此并行实现的运行时间为8到160秒,而顺序版本的运行时间仅为4秒(测试是在配备Intel i5处理器的机器上,在具有5个顶点的完全连接有向图上完成的)

以下是我对如此糟糕的表现的看法:

  • 我将有向图
    Graph
    传递给运行*dfs\u mod*的每个新进程。也许对多个进程中的一个有向图执行
    有向图:out_neights(Graph)
    会导致这种缓慢
  • 我将当前路径累积在一个列表中,并将其传递给每个新生成的*dfs\u mod*进程,也许传递这么多列表就是问题所在
  • 每次访问新顶点并将其添加到路径时,我都使用ETS表保存路径。ETS属性是
    ([bag,public,{write\u concurrency,true})
    ,但也许我做错了什么
  • 每次我访问一个新的顶点并将其添加到路径中时,我都会使用一个自定义函数检查一条路径(它基本上会检查路径中是否有标记为字母“n”的顶点出现在带有“m”的顶点之前,并根据结果返回
    true/false
    )。也许这会减慢速度
  • 我曾尝试在不收集
    done
    wait
    消息的情况下运行*dfs\u mod*,但是
    htop
    在shell中*dfs\u mod*返回
    ok
    后很长一段时间内显示了大量Erlang活动,因此我认为活动消息传递不会减慢速度

如何使我的并行dfs\u mod运行速度快于其顺序副本?


编辑:当我运行并行*dfs_mod*时,
pman
显示没有任何进程,尽管
htop
显示所有4个CPU线程都很忙。

没有代码就无法快速知道,但下面是失败原因的快速列表:

  • 您可能会混淆并行性和并发性。Erlang的模型不共享任何内容,并首先以并发性为目标(独立运行不同的代码单元)。并行性只是对此的优化(同时运行一些代码单元)通常,并行性会在更高的层次上形成,比如说,您想在50个不同的结构上运行排序函数,然后您决定运行50个顺序排序函数

  • 您可能会遇到同步问题或顺序瓶颈,从而有效地将并行解决方案更改为顺序解决方案

  • 复制数据、上下文切换和诸如此类的开销使您在并行性方面的收益相形见绌。前者尤其适用于将大型数据集分解成子数据集,然后再合并成大型数据集的情况。后者尤其适用于高度顺序的代码,如流程环基准测试所示

如果我想对此进行优化,我会尽量减少消息传递和数据复制


如果我是负责这项工作的人,我会保留顺序版本。它做它说应该做的事情,当它成为一个更大系统的一部分时,只要你有比核心更多的进程,并行性就会来自对排序函数的多次调用,而不是排序函数的分支。从长远来看,如果它是服务器或服务的一部分,那么g N次顺序版本的负面影响应该不会比并行版本的负面影响更大,并行版本最终会创建更多的进程来完成相同的任务,并可能导致系统过载。

速度的放缓比我预期的更为剧烈,但对于一个极小的5顶点图,你真的不能指望并行算法来提高性能E