为什么我的Scala命令式样式映射创建代码段比Java代码慢?

时间:2017-01-29 06:47:40

标签: java scala collections

我是Scala的新手,我正在尝试从IndexedSeq创建一个大地图,我发现在SO上提到功能样式地图创建比命令式Java风格慢得多,决定测试它我的自我。到目前为止,我发现Scala功能样式代码不仅速度慢,而且势在必行。我做错了什么,为什么我的Scala代码慢几倍?在我的家用计算机上,它运行时间为220毫秒(Java)和460毫秒(Scala)

Scala version

  private val testSize: Int = 1000000

  val seq: IndexedSeq[Int] = for (i <- 0 until testSize) yield Random.nextInt()

  val warmupMapt0 = System.nanoTime()

  var warmupMap: mutable.HashMap[Int, Int] = new mutable.HashMap[Int, Int]
  warmupMap.sizeHint(testSize)
  for (i <- 0 until testSize) warmupMap.put(i, seq(i))

  val t0 = System.nanoTime()
  var map: mutable.HashMap[Int, Int] = new mutable.HashMap[Int, Int]
  map.sizeHint(testSize)
  for (i <- 0 until testSize) map.put(i, seq(i))
  println((System.nanoTime() - t0)/ 1000000 + " ms.")

Java version

private static final int TEST_SIZE = 1_000_000;

public static void main(String[] args) {

    int[] ar = new int[TEST_SIZE];
    Random random = new Random();
    for (int i = 0; i < TEST_SIZE; i++) {
        ar[i] = random.nextInt();
    }

    Map<Integer, Integer> warmupMap = new HashMap<>(TEST_SIZE);
    for (int i = 0; i < TEST_SIZE; i++) {
        warmupMap.put(i, ar[i]);
    }

    Map<Integer, Integer> map = new HashMap<>(TEST_SIZE);
    long t0 = System.nanoTime();
    for (int i = 0; i < TEST_SIZE; i++) {
        map.put(i, ar[i]);
    }
    System.out.println((System.nanoTime() - t0) / 1_000_000 + " ms.");
}

2 个答案:

答案 0 :(得分:3)

我认为问题的一个来源是使用IndexedSeq。它默认由Vector实现,它通常是一个智能集合,但在你的情况下,它为创建&#34;数组&#34;添加了相当大的常数因子。数字,而不是通过索引访问它们。如果您希望您的代码更接近于java代码,则以下代码将成为答案:

val ar = new Array(TestSize)
for (i <- 0 until TestSize) ar(i) = Random.next()

我读过有关foreach循环优化的地方,无法找到哪里,基本上给予足够的预热运行foreach循环应该具有与while循环相比的效率,给定传递给它的函数可以内联。

修改

代码可以进一步简化:

val ar = Array.fill(TestSize)(Random.next())

Alexey Romanov提出的评论意见。

答案 1 :(得分:0)

这可能是for理解。在Scala中,它们以与Java中for循环完全不同的方式工作,并生成JVM无法很好地优化的代码。参见例如http://www.scalablescala.com/roller/scala/entry/why_is_using_for_foreachhttp://downloads.typesafe.com/website/presentations/ScalaDaysSF2015/T2_Rytz_Backend_Optimizer.pdf(从幻灯片37开始)。您可以使用while循环或宏库(如http://scala-blitz.github.io/https://github.com/non/spirehttps://github.com/nativelibs4java/scalaxy-streams来解决此问题。