gpt4 book ai didi

java - 在带有 Chronicle Map 的 Scala 中使用盒装/原子值

转载 作者:行者123 更新时间:2023-11-30 10:46:40 24 4
gpt4 key购买 nike

我们正在使用 ChronicleMap 来支持大量不同商店中的堆外持久化,但在最简单的用例中遇到了一些问题。

首先,这是我写的帮助创建更容易的助手:

import java.io.File
import java.util.concurrent.atomic.AtomicLong

import com.madhukaraphatak.sizeof.SizeEstimator
import net.openhft.chronicle.map.{ChronicleMap, ChronicleMapBuilder}

import scala.reflect.ClassTag

object ChronicleHelper {

def estimateSizes[Key, Value](data: Iterator[(Key, Value)], keyEstimator: AnyRef => Long = defaultEstimator, valueEstimator: AnyRef => Long = defaultEstimator): (Long, Long, Long) = {
println("Estimating sizes...")

val entries = new AtomicLong(1)
val keySum = new AtomicLong(1)
val valueSum = new AtomicLong(1)
var i = 0

val GroupSize = 5000

data.grouped(GroupSize).foreach { chunk =>

chunk.par.foreach { case (key, value) =>
entries.incrementAndGet()
keySum.addAndGet(keyEstimator(key.asInstanceOf[AnyRef]))
valueSum.addAndGet(valueEstimator(value.asInstanceOf[AnyRef]))
}

i += 1

println("Progress:" + i * GroupSize)
}

(entries.get(), keySum.get() / entries.get(), valueSum.get() / entries.get())
}

def defaultEstimator(v: AnyRef): Long = SizeEstimator.estimate(v)

def createMap[Key: ClassTag, Value: ClassTag](data: => Iterator[(Key, Value)], file: File): ChronicleMap[Key, Value] = {
val keyClass = implicitly[ClassTag[Key]].runtimeClass.asInstanceOf[Class[Key]]
val valueClass = implicitly[ClassTag[Value]].runtimeClass.asInstanceOf[Class[Value]]

val (entries, averageKeySize, averageValueSize) = estimateSizes(data)

val builder = ChronicleMapBuilder.of(keyClass, valueClass)
.entries(entries)
.averageKeySize(averageKeySize)
.averageValueSize(averageValueSize)
.asInstanceOf[ChronicleMapBuilder[Key, Value]]

val cmap = builder.createPersistedTo(file)

val GroupSize = 5000

println("Inserting data...")
var i = 0
data.grouped(GroupSize).foreach { chunk =>

chunk.par.foreach { case (key, value) =>
cmap.put(key, value)
}

i += 1

println("Progress:" + i * GroupSize)
}

cmap
}

def empty[Key: ClassTag, Value: ClassTag]: ChronicleMap[Key, Value] = {
val keyClass = implicitly[ClassTag[Key]].runtimeClass.asInstanceOf[Class[Key]]
val valueClass = implicitly[ClassTag[Value]].runtimeClass.asInstanceOf[Class[Value]]


ChronicleMapBuilder.of(keyClass, valueClass).create()
}


def loadMap[Key: ClassTag, Value: ClassTag](file: File): ChronicleMap[Key, Value] = {
val keyClass = implicitly[ClassTag[Key]].runtimeClass.asInstanceOf[Class[Key]]
val valueClass = implicitly[ClassTag[Value]].runtimeClass.asInstanceOf[Class[Value]]

ChronicleMapBuilder.of(keyClass, valueClass).createPersistedTo(file)
}
}

它使用 https://github.com/phatak-dev/java-sizeof用于物体尺寸估计。这是我们想要支持的用法:

object TestChronicle {
def main(args: Array[String]) {
def dataIterator: Iterator[(String, Int)] = (1 to 5000).toIterator.zipWithIndex.map(x => x.copy(_1 = x._1.toString))

ChronicleHelper.createMap[String, Int](dataIterator, new File("/tmp/test.map"))

}
}

但是它抛出一个异常:

[error] Exception in thread "main" java.lang.ClassCastException: Key must be a int but was a class java.lang.Integer [error] at net.openhft.chronicle.hash.impl.VanillaChronicleHash.checkKey(VanillaChronicleHash.java:661) [error] at net.openhft.chronicle.map.VanillaChronicleMap.queryContext(VanillaChronicleMap.java:281) [error] at net.openhft.chronicle.map.VanillaChronicleMap.put(VanillaChronicleMap.java:390) [error] at ...

我可以看出它可能与 Scala 的 Int 的原子性有关,而不是 Java 的 Integer,但我该如何绕过它?

斯卡拉 2.11.7

Chronicle map 3.8.0

最佳答案

  • 似乎怀疑在您的测试中它是 Iterator[(String, Int)](而不是 Iterator[(Int, String)]),因为键类型是 String 和值类型是Int,而错误消息是关于key的类型(int/Integer)
  • 如果错误消息显示 Key must be a %type% 这意味着您在第一个 ChronicleMapBuilder.of(keyType, valueType) 语句中配置了该类型。所以在你的情况下,这意味着你配置了 int.class (Class 对象,代表 Java 中的原始 int 类型),那不是允许,并为 map 的方法提供 java.lang.Integer 实例(可能您提供原始 int,但由于装箱,它们变成了 Integer) ,这是允许的。您应该确保为 ChronicleMapBuilder.of(keyType, valueType) 调用提供 java.lang.Integer.class(或其他一些 Scala 的类)。
  • 我不知道这个项目给出的规模估计:https://github.com/phatak-dev/java-sizeof ,但在任何情况下,您都应该以字节为单位指定对象将采用序列化形式的大小。序列化形式本身取决于默认序列化器,为 Chronicle Map 中的特定类型选择(并且可能在 Chronicle Map 版本之间更改),或为特定 ChronicleMapBuilder 配置的自定义序列化器。因此,使用任何关于键/值“大小”的信息来配置 Chronicle Map,而不是 Chronicle Map 本身,都是脆弱的。您可以使用以下过程更可靠地估计尺寸:

    public static <V> double averageValueSize(Class<V> valueClass, Iterable<V> values) {
    try (ChronicleMap<Integer, V> testMap = ChronicleMap.of(Integer.class, valueClass)
    // doesn't matter, anyway not a single value will be written to a map
    .averageValueSize(1)
    .entries(1)
    .create()) {
    LongSummaryStatistics statistics = new LongSummaryStatistics();
    for (V value : values) {
    try (MapSegmentContext<Integer, V, ?> c = testMap.segmentContext(0)) {
    statistics.accept(c.wrapValueAsData(value).size());
    }
    }
    return statistics.getAverage();
    }
    }

    你可以在这个测试中找到它:https://github.com/OpenHFT/Chronicle-Map/blob/7aedfba7a814578a023f7975ef15ba88b4d435db/src/test/java/eg/AverageValueSizeTest.java

    这个程序很老套,但目前没有更好的选择。

另一个建议:

  • 如果您的键或值是原始类型(整型、长型、 double 型,但已装箱)或任何其他大小始终相同的类型,则不应使用 averageKey/averageValue/averageKeySize/averageValueSize 方法,最好使用 constantKeySizeBySample/constantValueSizeBySample 方法。特别是对于 java.lang.IntegerLongDouble 即使这不是必需的,Chronicle Map 已经知道这些类型的大小是固定的。

关于java - 在带有 Chronicle Map 的 Scala 中使用盒装/原子值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36427895/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com