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