scala并行采集处理的性能

scala并行采集处理的性能,scala,parallel-processing,scala-collections,Scala,Parallel Processing,Scala Collections,在某些情况下,我需要一次处理数千条记录。有时,它可能有数百条,可能多达30000条记录。我正在考虑使用scala的并行集合。为了理解其中的区别,我写了一个简单的pgm,如下所示: object Test extends App{ val list = (1 to 100000).toList Util.seqMap(list) Util.parMap(list) } object Util{ def seqMap(list:List[Int]) = { val star

在某些情况下,我需要一次处理数千条记录。有时,它可能有数百条,可能多达30000条记录。我正在考虑使用scala的并行集合。为了理解其中的区别,我写了一个简单的pgm,如下所示:

object Test extends App{
  val list = (1 to 100000).toList
  Util.seqMap(list)
  Util.parMap(list)
}

object Util{
  def seqMap(list:List[Int]) = {
    val start = System.currentTimeMillis
    list.map(x => x + 1).toList.sum
    val end = System.currentTimeMillis
    println("time taken =" + (end - start))
    end - start
  }
  def parMap(list:List[Int]) = {
    val start = System.currentTimeMillis
    list.par.map(x => x + 1).toList.sum
    val end = System.currentTimeMillis
    println("time taken=" + (end - start))
    end - start
  }
}
我希望并行运行会更快。然而,我得到的结果是

time taken =32
time taken=127
机器配置

Intel i7 processor with 8 cores
16GB RAM
64bit Windows 8

我做错了什么?这不是一个正确的并行映射场景吗?

问题是您正在执行的操作太快(只需添加两个整数),因此并行化的开销大于好处。只有当操作速度较慢时,并行化才真正有意义

这样想:如果你有8个朋友,你在一张纸上给他们每人一个整数,让他们加上一个,把结果写下来,然后还给你,在给他们下一个整数之前,你会记录下来,你会花很多时间来回传递消息,所以你可以更快地添加自己


另外:千万不要对列表执行
.par
,因为并行化过程必须将整个列表复制到一个并行集合中,然后再将整个内容复制回来。如果你使用一个向量,那么它不必做额外的工作。

如果你在做基准测试,考虑使用JMH之类的东西来避免所有可能遇到的问题,如果你用程序的方式来测量它。例如,JIT可能会显著地改变您的结果,但只能在一些迭代之后

根据我的经验,如果输入不够大,并行收集通常会比较慢:如果输入很小,那么最初的拆分和最后的“组合”就没有回报

因此,再次使用不同大小的列表进行基准测试(尝试30000、100000和1000000)


此外,如果进行数值处理,请考虑使用<代码>数组(而不是<代码>列表)和<>代码> (而不是<代码> MAP)。这些对底层JVM来说是“更原生的”(=更快),而在您的例子中,您可能正在测量垃圾收集器的性能。至于

数组
您可以将操作的结果“就地”存储。

并行化列表的开销证明比按顺序处理
x+1
操作更耗时

还考虑这种修改,其中包括大约超过1毫秒的操作,

case class Delay() {
  Thread.sleep(1)
}
替换

list.map(x => x + 1).toList.sum

现在对于
val list=(1到10000)。toList
(注意10000而不是100000),在一台8GB四核机器中

scala> Util.parMap(list)
time taken=3451
res4: Long = 3451

scala> Util.seqMap(list)
time taken =10816
res5: Long = 10816

我们可以推断(更好的猜测)对于具有耗时操作的大型集合,与顺序集合处理相比,并行化集合的开销不会显著影响运行时间。

并行集合在执行耗时的操作之前初始化线程


这样,当通过并行集合执行少量元素或操作的操作占用时间较短时,并行集合将执行较慢的

“也:永远不做。列表上的PAR”。让我说,我把成千上万的记录作为一个列表,这是不是意味着先转换为向量,然后在它上面做PAR会更快?如果你在列表中调用PAR,它就被迫在它可以做任何事情之前复制整个列表,然后它必须将它复制回去,以便它可以返回一个列表给你。手动执行转换可能不会使它变得更好,但如果使用向量,则不必执行任何复制。事实上,我会反对每一个使用列表;向量基本上在所有方面都更好。还有一个疑问。如果在映射操作中有一些db查询,该怎么办。将该地图并行化将对它有积极的帮助?对于EG:Valm SalEvistList.PARMAP { item = > //做一些与“item”的操作,得到一些结果RES’/ /用结果RES'}查询数据库,我有一些场景需要生成一些报告。映射中的逻辑有点复杂,但是在得到复杂的逻辑之后,我需要使用该结果调用数据库。所以我想知道,在这种情况下会不会有使用并行映射的PBLM。(注意:我现在不使用连接池。)
scala> Util.parMap(list)
time taken=3451
res4: Long = 3451

scala> Util.seqMap(list)
time taken =10816
res5: Long = 10816