在Chronicle Map上迭代非常慢

时间:2017-05-14 17:37:34

标签: java chronicle chronicle-map

我看到在Chronicle Map上迭代的时间很慢 - 在下面的示例中,每次迭代93ms,超过了我的2013 MacbookPro上的1M条目。我想知道是否有更好的迭代方法或者我做错了什么或者这是否是预期的?我知道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");

}

输出: 完成插入 完成启动 经历:93327 1000次迭代

1 个答案:

答案 0 :(得分:1)

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

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

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