Эффективная сериализация нативных массивов java с java.io

Я должен вопрос о сериализации Java.

Я просто записываю 10 массивов размера int[] array = new int[2^28] в мой harddik (я знаю, что это довольно большой, но мне это нужно так), используя FileOutputStream и BufferedOutputStream в сочетании с Dataoutputstream, Перед каждой сериализацией я создаю новый FileOutputstream и все остальные потоки, а затем закрываю и очищаю свои потоки.

Проблема: первая сериализация занимает около 2 секунд, затем она увеличивается до 17 секунд и остается на этом уровне. В чем здесь проблема? Если я углублюсь в код, то увижу, что FileOutputStreams тратит огромное количество времени на writeByte (...). Это из-за кеширования HDD (полное)? Как я могу избежать этого? Могу ли я очистить это?

Вот мой простой код:

    public static void main(String[] args) throws IOException {

    System.out.println("### Starting test");

    for (int k = 0; k < 10; k++) {
        System.out.println("### Run nr ... " + k);

        // Creating the test array....
        int[] testArray = new int[(int) Math.pow(2, 28)];

        for (int i = 0; i < testArray.length; i++) {
            if (i % 2 == 0) {
                testArray[i] = i;
            }
        }

        BufferedDataOutputStream dataOut = new BufferedDataOutputStream(
                new FileOutputStream("e:\\test" + k + "_" + 28 + ".dat"));

        // Serializing...
        long start = System.nanoTime();
        dataOut.write(testArray);

        System.out.println((System.nanoTime() - start) / 1000000000.0
                + " s");

        dataOut.flush();
        dataOut.close();
    }
}

где dataOut.write(int[], 0, end)

    public void write(int[] i, int start, int len) throws IOException {

    for (int ii = start; ii < start + len; ii += 1) {
        if (count + 4 > buf.length) {
            checkBuf(4);
        }

        buf[count++] = (byte) (i[ii] >>> 24);
        buf[count++] = (byte) (i[ii] >>> 16);
        buf[count++] = (byte) (i[ii] >>> 8);
        buf[count++] = (byte) (i[ii]);

    }

}

и `protected void checkBuf(int need) выдает IOException {

    if (count + need > buf.length) {
        out.write(buf, 0, count);
        count = 0;
    }
}`

BufferedDataOutputStream расширяет BufferedOutputStream поставляется вместе со структурой соответствия. Он просто комбинирует BufferedOutputStream с DataOutputStream, чтобы уменьшить количество вызовов методов, когда вы пишете большие массивы (что делает его намного быстрее... до 10 раз...).

Вот вывод:

Начальный тест

НАЧАЛО РАБОТЫ 0

2,001972271

НАЧАЛО РАБОТЫ 1

1,986544604

НАЧАЛО РАБОТЫ 2

+15,663881232

НАЧАЛО РАБОТЫ 3

+17,652161328

НАЧАЛО РАБОТЫ 4

+18,020969301

НАЧАЛО РАБОТЫ 5

+11,647542466

НАЧАЛО РАБОТЫ 6

Почему время так сильно увеличивается?

Спасибо,

Eeth

2 ответа

В этой программе я заполняю 1 ГБ как значения int и "заставляю" их записывать на диск.

String dir = args[0];
for (int i = 0; i < 24; i++) {
  long start = System.nanoTime();
  File tmp = new File(dir, "deleteme." + i);
  tmp.deleteOnExit();
  RandomAccessFile raf = new RandomAccessFile(tmp, "rw");
  final MappedByteBuffer map = raf.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 1 << 30);
  IntBuffer array = map.order(ByteOrder.nativeOrder()).asIntBuffer();
  for (int n = 0; n < array.capacity(); n++)
    array.put(n, n);

  map.force();

  ((DirectBuffer) map).cleaner().clean();
  raf.close();
  long time = System.nanoTime() - start;
  System.out.printf("Took %.1f seconds to write 1 GB%n", time / 1e9);
}

с каждым файлом, загруженным на диск, они занимают примерно одинаковое количество времени каждый.

Took 7.7 seconds to write 1 GB
Took 7.5 seconds to write 1 GB
Took 7.7 seconds to write 1 GB
Took 7.9 seconds to write 1 GB
Took 7.6 seconds to write 1 GB
Took 7.7 seconds to write 1 GB

Однако, если я закомментирую map.force(); Я вижу этот профиль.

Took 0.8 seconds to write 1 GB
Took 1.0 seconds to write 1 GB
Took 4.9 seconds to write 1 GB
Took 7.2 seconds to write 1 GB
Took 7.0 seconds to write 1 GB
Took 7.2 seconds to write 1 GB
Took 7.2 seconds to write 1 GB

Похоже, что он будет буфер около 2,5 ГБ, что составляет около 10% моей основной памяти, прежде чем он замедлится.


Вы можете очистить кэш, дождавшись окончания предыдущих записей.

Как правило, у вас есть 1 ГБ данных, а скорость записи на диск составляет около 60 МБ / с, что является разумным для жесткого диска SATA. Если вы получаете скорость выше этой, то это потому, что данные на самом деле не записаны на диск и фактически находятся в памяти.

Если вы хотите, чтобы это было быстрее, вы можете использовать отображенный файл памяти. Это дает преимущество записи на диск в фоновом режиме, так как вы заполняете "массив", т. Е. Запись может быть завершена почти сразу, как только вы закончите установку значений.

Другой вариант - получить более быстрый диск. Один 250 ГБ SSD-накопитель может поддерживать скорость записи около 200 МБ / с. Использование нескольких дисков в конфигурации RAID также может увеличить скорость записи.

Первая запись может просто заполнить кэш вашего жесткого диска, фактически не записывая на диск.

Другие вопросы по тегам