Очень медленная итерация на карте хроники

Я наблюдаю очень медленные итерации по карте хроники - в приведенном ниже примере 93 мс на итерацию по 1 млн записей на моем MacbookPro 2013 года. Мне интересно, есть ли лучший способ итерации или что-то я делаю не так или это ожидается? Я знаю, что Chronicle Map не оптимизирована для итерации, но этот билет, полученный несколько лет назад, заставил меня ожидать гораздо более быстрое время итерации. Пример игрушки ниже:

    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 ответ

Ваши результаты: 93 миллисекунды на 1 миллион ключей в точности совпадают с результатами теста здесь: http://jetbrains.github.io/xodus/, так что он находится в ожидаемом поле. 93 мс / 1 м ключей - это 93 нс на ключ, это "очень медленно" по сравнению с чем? Ваша карта содержит 16 МБ полезной нагрузки, а ее общий размер вне кучи составляет ~ 30 МБ (к вашему сведению, map.offHeapMemoryUsed()), это намного больше, чем объем памяти L3 в потребительских ноутбуках, поэтому скорость итерации зависит от времени ожидания основной памяти. Итерация Chronicle Map в основном не последовательная, поэтому предварительная выборка из памяти не работает. Я создал проблему по этому поводу.

Также несколько заметок о вашем коде:

  • В вашем случае размер значения карты является постоянным, поэтому вы должны использовать constantValueSizeBySample(ByteBuffer.allocate(12)) вместо averageValueSize(), Даже если размер значения карты не был постоянным, предпочтительно использовать averageValue() вместо averageValueSize()потому что вы не можете быть уверены, сколько байтов сериализаторы используют для значений.
  • Ваше значение представляется хорошим вариантом использования для интерфейсов значений с двумя полями. Более того, вы уже используете интерфейс значения в качестве типа ключа - IntValue,
  • Делать тесты, используя JMH
Другие вопросы по тегам