[英]Scala enumeration map implementation
Java 有EnumMap
- 專為鍵是enum
類型的情況而設計的特殊Map
實現(請參閱類聲明EnumMap<K extends Enum<K>,V>
)。 例如, java.util.HashMap
的主要優勢是內存和性能效率,因為它提前知道鍵的數量,因為它們是在枚舉中聲明的,所以它內存緊湊且速度更快,因為不需要擴展內部表並解決散列沖突。
我想知道這個 Java 實現是否有任何開箱即用的 Scala 實現,但是有 Scala 的Enumeration
和immutable.Map
接口。 也許任何外部庫實現或任何方式來創建自己的實現與接近內存和性能結果?
非常感謝您提前提供幫助!
Enumeratum 的公開問題EnumSet/EnumMap #113提供了一個信息基准
[info] MapComparisons.enumeratumScalaMapGet avgt 30 9.830 ± 0.207 ns/op
[info] MapComparisons.jEnumEnumMapGet avgt 30 4.745 ± 0.685 ns/op
[info] MapComparisons.jEnumScalaMapGet avgt 30 12.204 ± 0.186 ns/op
勞埃德梅塔州
所以目前的情況是 Java EnumMap 和 EnumSet 比普通的舊 Scala Set 和帶有 Enumeratum 的 Maps 快大約 2 倍,但由於我們仍處於 10 納秒以下的范圍內,因此可以說這里的性能獲勝似乎是合理的除非在超級邊緣情況下,否則不會成為瓶頸。
我嘗試復制 lloydmeta 的基准測試並使用 Scala 2.13 enumeratum 1.5.15 得到以下結果
sbt "jmh:run -i 10 -wi 10 -f 2 -t 1 -prof gc bench.So60374058"
平均時間,時間/操作
enumeratumScalaMapGet avgt 20 8.284 ± 0.071 ns/op
jEnumEnumMapGet avgt 20 2.883 ± 0.023 ns/op
jEnumScalaMapGet avgt 20 7.361 ± 0.273 ns/op
vanillaScalaMapGet avgt 20 6.650 ± 0.323 ns/op
內存分配率
enumeratumScalaMapGet:·gc.alloc.rate avgt 20 1753.262 ± 14.548 MB/sec
jEnumEnumMapGet:·gc.alloc.rate avgt 20 ≈ 10⁻⁴ MB/sec
jEnumScalaMapGet:·gc.alloc.rate avgt 20 1976.491 ± 70.259 MB/sec
vanillaScalaMapGet:·gc.alloc.rate avgt 20 2190.644 ± 105.208 MB/sec
我們注意到jEnumScalaMapGet
自 2017 年以來似乎已經趕上了enumeratumScalaMapGet
,以及jEnumEnumMapGet
的微不足道的內存分配。
基准源:
public enum JAgeGroup {
Baby,
Toddler,
Teenager,
Adult,
Senior
}
和
import java.util
import java.util.concurrent.TimeUnit
import example.JAgeGroup
import org.openjdk.jmh.annotations._
import org.openjdk.jmh.infra.Blackhole
import enumeratum._
object AgeGroupVanilla extends Enumeration {
type AgeGroupVanilla = Value
val Baby, Toddler, Teenager, Adult, Senior = Value
}
sealed trait AgeGroup extends EnumEntry
case object AgeGroup extends Enum[AgeGroup] {
val values = findValues
case object Baby extends AgeGroup
case object Toddler extends AgeGroup
case object Teenager extends AgeGroup
case object Adult extends AgeGroup
case object Senior extends AgeGroup
}
@State(Scope.Thread)
@BenchmarkMode(Array(Mode.AverageTime))
@OutputTimeUnit(TimeUnit.NANOSECONDS)
class So60374058 {
private val jEnumEnumMap = {
val m: util.EnumMap[JAgeGroup, String] = new util.EnumMap(classOf[JAgeGroup])
JAgeGroup.values().foreach(e => m.put(e, e.name()))
m
}
private val jEnumScalaMap = Map(JAgeGroup.values().map(e => e -> e.name()): _*)
private val ageGroupScalaMap = Map(AgeGroup.values.map(e => e -> e.entryName): _*)
private val vanillaScalaMap = AgeGroupVanilla.values.map(e => e -> e.toString).toMap
private def randomFrom[A](seq: Seq[A]): A = {
seq(scala.util.Random.nextInt(seq.size))
}
private var jEnum: JAgeGroup = _
private var ageGroupEnum: AgeGroup = _
private var vanillaEnum: AgeGroupVanilla.AgeGroupVanilla = _
@Setup(Level.Trial)
def setup(): Unit = {
jEnum = randomFrom(JAgeGroup.values())
ageGroupEnum = randomFrom(AgeGroup.values)
vanillaEnum = randomFrom(AgeGroupVanilla.values.toSeq)
}
@Benchmark
def jEnumEnumMapGet(bh: Blackhole): Unit = bh.consume {
jEnumEnumMap.get(jEnum)
}
@Benchmark
def jEnumScalaMapGet(bh: Blackhole): Unit = bh.consume {
jEnumScalaMap.get(jEnum)
}
@Benchmark
def enumeratumScalaMapGet(bh: Blackhole): Unit = bh.consume {
ageGroupScalaMap.get(ageGroupEnum)
}
@Benchmark
def vanillaScalaMapGet(bh: Blackhole): Unit = bh.consume {
vanillaScalaMap.get(vanillaEnum)
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.