java - 编年史 map 上的迭代速度非常慢

标签 java chronicle chronicle-map

我发现历史记录 map 的迭代速度非常慢 - 在下面的示例中,在我的 2013 MacbookPro 上,每次迭代超过 100 万个条目需要 93 毫秒。我想知道是否有更好的迭代方法或者我做错了什么或者这是否是预期的?我知道 Chronicle Map 没有针对迭代进行优化,但是 this ticket几年前让我期待更快的迭代时间。下面的玩具示例:

    public static void main(String[] args) throws Exception {
    int numEntries = 1_000_000;
    int numIterations = 1_000;
    int avgEntrySize = BitUtil.SIZE_OF_LONG + BitUtil.SIZE_OF_INT;
    ChronicleMap<IntValue, ByteBuffer> map = ChronicleMap.of(IntValue.class, ByteBuffer.class)
            .name("test").entries(numEntries).averageValueSize(avgEntrySize)
            .putReturnsNull(true).create();
    IntValue value = Values.newHeapInstance(IntValue.class);
    ByteBuffer buffer = ByteBuffer.allocate(avgEntrySize);
    for (int i = 0; i < numEntries; i++) {
        value.setValue(i);
        buffer.clear();
        buffer.putLong(i);
        buffer.putInt(i);
        buffer.flip();
        map.put(value, buffer);
    }
    System.out.println("Finished insertion");

    for (int i = 0; i < numIterations; i++) {
        map.forEachEntry(entry -> {
            Data<ByteBuffer> data = entry.value();
            ByteBuffer val = data.get();
        });
    }
    System.out.println("Finished priming");
    long start = System.currentTimeMillis();
    for (int i = 0; i < numIterations; i++) {
        map.forEachEntry(entry -> {
            Data<ByteBuffer> data = entry.value();
            ByteBuffer val = data.get();
        });
    }
    System.out.println(
            "Elapsed: " + (System.currentTimeMillis() - start) + " for " + numIterations
                    + " iterations");

}

输出: 插入完成 底漆完成 已用时间:1000 次迭代为 93327

最佳答案

您的结果:每 100 万个键 93 毫秒与此处的基准测试结果完全匹配:http://jetbrains.github.io/xodus/#benchmarks ,所以它在预期范围内。 93 ms/1m 键是每个键 93 ns,与什么相比它“非常慢”?您的映射包含 16 MB 的有效负载,其总堆外大小约为 30 MB(仅供引用,您可以通过 map.offHeapMemoryUsed() 检查),这远远大于 L3 内存的容量消费类笔记本电脑,因此迭代速度受到主内存延迟的限制。 Chronicle Map的迭代主要不是顺序的,因此内存预取不起作用。 I've created an issue about this.

还有一些关于您的代码的注释:

  • 在您的情况下,映射的值大小是恒定的,因此您应该使用 constantValueSizeBySample(ByteBuffer.allocate(12)) 而不是 averageValueSize()。即使映射值大小不是恒定的,也最好使用 averageValue() 而不是 averageValueSize(),因为您无法确定序列化程序使用多少字节值(value)观。
  • 您的值似乎是 value interfaces 的一个很好的用例有两个字段。此外,您已经使用值接口(interface)作为键类型 - IntValue
  • 使用 JMH 进行基准测试

关于java - 编年史 map 上的迭代速度非常慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43966985/

相关文章:

java - 多个 fragment 可以共享一个 XML 布局吗

java - 使用 Chronicle Map 作为微服务之间数据共享的手段

java - 一个关于URL的问题

java - Chronicle Queue 可以像 RMI 一样使用吗?

java - Chronicle:反序列化期间对象未初始化

java - 使用基元的编年史 map

java - 在 OpenHTF ChronicleMap 上设置最大条目数

java - 在 Java 中用 Chronicle-Map 替换 Roaring64NavigableMap 的正确方法是什么?

java - Java 中的 ZigZag 解码/编码

java - 为 Eclipse 安装 Maven 集成时出错