scala - 为什么 Scala HashMap 很慢?

标签 scala hashmap java-8 scala-2.11

对此可以做些什么?

我已经运行了一些测试,似乎 Scala Hashmap 比 Java HashMap 慢得多。请证明我错了!

对我来说,Hashmap 的全部意义在于从给定的键快速访问一个值。所以我发现自己在速度很重要时诉诸于使用 Java HashMap,这有点令人难过。我没有足够的经验可以肯定地说,但似乎您混合 Java 和 Scala 的次数越多,您可能面临的问题就越多。

test("that scala hashmap is slower than java") {
    val javaMap = new util.HashMap[Int,Int](){
      for (i <- 1 to 20)
      put(i,i+1)
    }

    import collection.JavaConverters._
    val scalaMap = javaMap.asScala.toMap

    // check is a scala hashmap
    assert(scalaMap.getClass.getSuperclass === classOf[scala.collection.immutable.HashMap[Int,Int]])

    def slow = {
      val start = System.nanoTime()
      for (i <- 1 to 1000) {
        for (i <- 1 to 20) {
          scalaMap(i)
        }
      }
      System.nanoTime() - start
    }

    def fast = {
      val start = System.nanoTime()
      for (i <- 1 to 1000) {
        for (i <- 1 to 20) {
          javaMap.get(i)
        }
      }
      System.nanoTime() - start
    }

    val elapses: IndexedSeq[(Long, Long)] = {
      (1 to 1000).map({_ => (slow,fast)})
    }

    var elapsedSlow = 0L
    var elapsedFast = 0L
    for ((eSlow,eFast) <- elapses) {
      elapsedSlow += eSlow
      elapsedFast += eFast
    }

    assert(elapsedSlow > elapsedFast)

    val fraction : Double = elapsedFast.toDouble/elapsedSlow
    println(s"slower by factor of: $fraction")
}

我错过了什么吗?

答案摘要

到目前为止,当将 Java 8 与 Scala 2.11 进行比较时,Java HashMap 的查找速度(对于少量键)似乎比 Scala 产品更快——LongMap 除外(如果您的键是 Ints/Longs)。

性能差异并不是很大,以至于在大多数用例中都应该很重要。希望 Scala 能够提高他们 Maps 的速度。同时,如果您需要性能(使用非整数键),请使用 Java。

整数键,n=20
Long(60)、Java(93)、Open(170)、MutableSc(243)、ImmutableSc(317)

case 对象键,n=20
Java(195), AnyRef(230)

最佳答案

首先:使用nanoTime 进行JVM 基准测试是容易出错。使用微基准测试框架,例如 Thyme , CaliperJMH

第二:您正在将可变的 java 哈希映射与不可变的 scala 哈希映射进行比较。不可变集合可以非常快,但在某些情况下,它们永远不会像可变数据结构一样快。

这是可变 java 哈希映射与不可变 scala 哈希映射的适当微基准测试:https://gist.github.com/rklaehn/26c277b2b5666ec4b372

如您所见,scala 不可变映射比 java 可变映射要快一些。请注意,一旦您使用更大的 map ,情况就不会如此,因为不可变数据结构必须做一些妥协才能启用 structural sharing .我猜在这两种情况下,主要的性能问题是将整数装箱为整数。

更新:如果你真的想要一个以整数为键的可变散列 hap,scala 集合库中的正确选择是 scala.collection.mutable.LongMap .它使用 long as 键,并且比通用 Map 具有更好的性能,因为它不必对值进行装箱。查看要点的结果。

更新 2:如果您的 key 从 AnyRef 扩展(例如字符串),那么高性能可变映射的最佳选择是 scala.collection.mutable.AnyRefMap

关于scala - 为什么 Scala HashMap 很慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28744990/

相关文章:

java - Java 8 Lambda 表达式的 Groovy 等价物

除列表之外的序列上的 Scala 模式匹配

java - 在 java 中使用 HashMap<Object,Object> 时,键的类型是什么?

java - 如何过滤流映射期间抛出异常的元素

java - 如何避免重复代码初始化 hashmap 的 hashmap?

c++ - 使用 Autoconf 处理已弃用的包含

javascript - Playframework:通过Javascript通过location.href调用 Controller 的action

scala - Actor 模型不是一种反模式吗,因为“一劳永逸”的风格迫使 Actor 记住一种状态?

scala - 拆分没有索引越界异常

java - 更新 Java HashMap 键