对于Scala 2.13,更新具有数百万次更新的LongMap、HashMap或TrieMap的最快方法是什么?
目标 我有一个可变地图[Long,Long],有数百万个条目。我需要用数百万次更新进行多次迭代更新。我想尽快做到这一点 背景 目前,最快的方法是使用单线程mutable.LongMap[Long]。此类型针对作为键的长类型进行了优化 其他映射类型看起来比较慢——但我可能没有正确地实现它们,因为我试图同时和/或并行地进行更新,但没有成功。并行更新映射可能没有实际发生,或者在Scala中不可能 按照从最快到最慢的顺序:对于Scala 2.13,更新具有数百万次更新的LongMap、HashMap或TrieMap的最快方法是什么?,scala,parallel-processing,parallel.foreach,scala-2.13,Scala,Parallel Processing,Parallel.foreach,Scala 2.13,目标 我有一个可变地图[Long,Long],有数百万个条目。我需要用数百万次更新进行多次迭代更新。我想尽快做到这一点 背景 目前,最快的方法是使用单线程mutable.LongMap[Long]。此类型针对作为键的长类型进行了优化 其他映射类型看起来比较慢——但我可能没有正确地实现它们,因为我试图同时和/或并行地进行更新,但没有成功。并行更新映射可能没有实际发生,或者在Scala中不可能 按照从最快到最慢的顺序: 长地图[长](从上方) TrieMap[长,长] ParTrieMap[长,长]
import java.util.Calendar
import scala.collection.mutable
object DictSpeedTest2 {
//helper constants
val million: Long = 1000000
val billion: Long = million * 1000
//config
val garbageCollectionWait = 3
val numEntries: Long = million * 10 //may need to increase JVM memory with something like: -Xmx32g
val maxValue: Long = billion * million // max Long = 9223372036854775807L
// this is 1000000000000000L
def main(args: Array[String]): Unit = {
//generate random data; initial entries in a; updates in b
val a = genData(numEntries, maxValue, seed = 1000)
val b = genData(numEntries, maxValue, seed = 9999)
//initialization
val dict = new mutable.LongMap[Long]()
a.foreach(x => dict += (x._1 -> x._2))
//run and time test
println("start test: " + Calendar.getInstance().getTime)
val start = System.currentTimeMillis
b.foreach(x => dict += (x._1 -> x._2)) //updates
val end = System.currentTimeMillis
//print runtime
val durationInSeconds = (end - start).toFloat / 1000 + "s"
println("end test: " + Calendar.getInstance().getTime + " -- " + durationInSeconds)
}
def genData(n: Long, max: Long, seed: Long): Array[(Long, Long)] = {
val r = scala.util.Random
r.setSeed(seed) //deterministic generation of arrays
val a = new Array[(Long, Long)](n.toInt)
a.map(_ => (r.nextInt(), r.nextInt()) )
}
}
当前计时
带有上述代码的LongMap[Long]将在我的2018 MacBook Pro上在以下时间完成:
- 约3.5秒,含numEntries=1000万
- 约100秒,含numEntries=1亿
对于此类库,对于Int/Int对的基准测试结果并不过时。首先,这远不是测试两种实现性能的合适方法。看看合适的基准测试工具,比如ScalaMeter。第二,易变性+并发性/并行性将导致许多麻烦。这可能有助于描述您在此尝试建模的内容,以及为什么在此用例中性能对您来说太重要。但您仍然没有回答此可变映射的目的是什么以及为什么性能太重要。您是否考虑过将该状态移到应用程序之外。例如数据库,例如Mongo?或者更适合像Redis这样的分布式缓存?或者使用其他技术来处理大量的数据,比如Spark或Scio?是的,我指的更多的是在代码之外保留所有突变的能力,有时你可以用不同的方式优化算法。如果您使用AWS,Scio将不会为您工作,因为它与GCP中的数据流服务集成良好。PS:你也可以看看流媒体是否有帮助,看看fs2、Monix或Akka Streams。我对Akka演员非常熟悉,也涉猎过Streams库。我真的想保持这个模块中的状态。离开应用程序会减慢速度,需要重新进入一些状态。延迟在这里很重要。我导入了FastUtil,获得了几乎瞬间8倍的速度提升。那就足够了。前几天我找到了那篇文章。FastUtil可能正是我想要的。我打算今天晚些时候测试它。FastUtil真的很快。这里没有虚假广告。谢谢