Scala中并行集合的效率/可伸缩性(图形)

时间:2012-03-16 18:53:09

标签: scala graph scala-collections parallel-collections

所以我一直在使用Scala中的并行集合来处理我正在处理的图形项目,我已经定义了图形类的基础知识,它目前正在使用scala.collection.mutable.HashMap,其中关键是Int,值为ListBuffer[Int](邻接列表)。 (编辑:此后已更改为ArrayBuffer[Int]

几个月前,我在C ++中做了类似的事情,std::vector<int, std::vector<int> >

我现在要做的是在图形中的所有顶点对之间运行一个度量,所以在C ++中我做了类似这样的事情:

// myVec = std::vector<int> of vertices
for (std::vector<int>::iterator iter = myVec.begin(); iter != myVec.end(); ++iter) {
    for (std::vector<int>::iterator iter2 = myVec.begin(); 
        iter2 != myVec.end(); ++iter2) {
        /* Run algorithm between *iter and *iter2 */
    }
}

我在Scala中做了同样的事情,并行化,(或尝试过):

// vertexList is a List[Int] (NOW CHANGED TO Array[Int] - see below)
vertexList.par.foreach(u =>
  vertexList.foreach(v =>
    /* Run algorithm between u and v */
  )
)

C ++版本显然是单线程的,Scala版本有.par所以它使用并行集合,并且在8个核心(同一台机器)上是多线程的。但是,C ++版本在大约3天的时间内处理了305,570对,而到目前为止,Scala版本在17个小时内仅处理了23,573对。

假设我正确地完成了math,单线程C ++版本比Scala版本快大约3倍。 Scala真的比C ++慢得多,或者我完全误用了Scala(我最近刚开始 - 我在Scala编程大约300页)?

谢谢! -kstruct

编辑要使用while循环,我可以执行类似..

的操作
// Where vertexList is an Array[Int]
vertexList.par.foreach(u =>
  while (i <- 0 until vertexList.length) {
    /* Run algorithm between u and vertexList(i) */
  }
}

如果你们的意思是对整个事情使用while循环,对于whiles是否有等效的.par.foreach

EDIT2 等一下,那段代码甚至不对 - 我的坏。如何使用while循环并行化这个?如果我有一些跟踪迭代的var i,那么所有线程都不会共享i吗?

3 个答案:

答案 0 :(得分:4)

根据您的评论,我看到您在每个算法运行结束时更新共享的可变HashMap。如果您随意进行散步,则共享Random也是一个争用点。

我建议进行两项更改:

  1. 使用.map.flatMap返回不可变集合,而不是修改共享集合。
  2. 使用ThreadLocalRandom(来自AkkaJava 7)减少对随机数生成器的争用
  3. 检查算法的其余部分是否存在其他可能的争用点。
  4. 您也可以尝试并行运行内部循环。但是在不知道你的算法的情况下,很难知道这会有所帮助还是有害。幸运的是,运行并行和顺序集合的所有组合非常简单;只需在下面的代码中切换pVertexListvertexList
  5. 这样的事情:

    val pVertexList = vertexList.par
    val allResult = for {
      u <- pVertexList
      v <- pVertexList
    } yield {
      /* Run algorithm between u and v */
      ((u -> v) -> result)
    }
    

    allResult将为ParVector[((Int, Int), Int)]。您可以在其上调用.toMap将其转换为Map

答案 1 :(得分:2)

为什么可变?我不认为Scala 2.9.x上有一个很好的并行可变映射 - 特别是因为这样的数据结构被添加到即将到来的Scala 2.10中。

另一方面......你有List[Int]?不要使用它,使用Vector[Int]。另外,你确定你不是在其他地方浪费时间,从可变映射和缓冲区转换成不可变列表吗? Scala数据结构与C ++不同,因此您可能会遇到代码中其他地方的复杂性问题。

最后,当他询问争用时,我认为dave可能会出现问题。如果你有争用,并行可能会让事情变得更慢。如果使其并行,它的运行速度/速度会更快/更慢?如果使它不平行使它更快,那么你很可能会遇到争用问题。

答案 2 :(得分:0)

我对此并不完全确定,但我认为foreach循环中的foreach循环相当慢,因为会创建大量对象。请参阅:http://scala-programming-language.1934581.n4.nabble.com/for-loop-vs-while-loop-performance-td1935856.html

尝试使用while循环重写它。

此外,列表仅对头部访问有效,阵列可能更快。