Производительность Java - Как записать большой массив на диск / SDCard с высокой производительностью? - PullRequest
3 голосов
/ 19 декабря 2010

Есть ли в Java способ записи на диск большого массива, скажем, целых чисел?Я делаю это на Android, и не нашел метода, который был бы близок к собственному коду C.

Полученный файл не нужно переносить на разные машины с разными представлениями, так что логически просто массовая записьбазовых байтов должно быть достаточно.Но я не знаю, как сделать это эффективно с Java.

Я попытался выполнить поиск в сети и протестировал следующее:

  • Сериализация - очень медленная, как и ожидалось.
  • Использование NIO - все еще медленно - трассировка Android показывает операции по одному на целое число:

Заранее спасибо


Код NIO:

int[] array = new array[10000000];

...

raf = new RandomAccessFile(ti.testFileName, "rw");
chan = raf.getChannel();
MappedByteBuffer out = chan.map(FileChannel.MapMode.READ_WRITE, 0, array.length*4);
ib = out.asIntBuffer();
ib.put(array);
out.force();
raf.close();

Ответы [ 4 ]

3 голосов
/ 20 декабря 2010

Вы сказали, что это медленно, но скорость, скорее всего, будет зависеть от скорости вашей дисковой подсистемы. Вы должны быть в состоянии записать 40 МБ на обычный диск примерно за полсекунды для фиксации на диск.

Следующее использует NIO и занимает 665 мс для записи и 62 мс на рабочей станции. Чтение и запись перемешивают один и тот же объем данных, но чтение может извлечь свои данные из кэша ОС, различие в том, сколько времени потребуется для записи на диск.

int[] ints = new int[10 * 1000 * 1000];
long start = System.nanoTime();

ByteBuffer byteBuffer = ByteBuffer.allocateDirect(ints.length*4+4);
byteBuffer.putInt(ints.length);
IntBuffer intBuffer = byteBuffer.asIntBuffer();
intBuffer.put(ints);
byteBuffer.position(0);

FileChannel fc = new FileOutputStream("main.dat").getChannel();
fc.write(byteBuffer);
fc.force(false);
fc.close();
long time = System.nanoTime() - start;
System.out.println("Write time " + time / 1000 / 1000 + " ms.");

long start2 = System.nanoTime();
FileChannel fc2 = new FileInputStream("main.dat").getChannel();
ByteBuffer lengthBuffer = ByteBuffer.allocate(4);
while(lengthBuffer.remaining()>0) fc2.read(lengthBuffer);
int length = lengthBuffer.getInt(0);

int[] ints2 = new int[length];
ByteBuffer buffer2 = ByteBuffer.allocateDirect(length*4);
while(buffer2.remaining()>0 && fc2.read(buffer2) > 0);
buffer2.flip();
buffer2.asIntBuffer().get(ints2);
long time2 = System.nanoTime() - start2;
System.out.println("Read time " + time2 / 1000 / 1000 + " ms.");

Я добавил длину в начало файла, чтобы ее не предполагалось. Кстати: в записи была ошибка, которую я исправил.

1 голос
/ 20 декабря 2010

Я понятия не имею о реализации Android, но в стандартной Java старый добрый IO часто превосходит NIO.

Например, я считаю, что следующий код должен быть относительно быстрым, если у вас есть массив байтов:

byte[] bytes = new byte[10000];
// ...
FileOutputStream out = new FileOutputStream(...);
try {
    out.write(bytes);
} finally {
    out.close();
}

Имейте в виду, что это будет блокировать, пока не будет записан весь массив байтов. Но вы не говорите, является ли неблокирующее поведение проблемой или нет.

Еще одна вещь, которую вы не упоминаете, это то, как вы собираетесь кодировать целые числа при записи в файл. Вам необходимо выполнить кодирование в памяти перед записью в файл, но возможно, что массив слишком велик, чтобы кодировать все сразу, и в этом случае вы можете кодировать / записывать блоки по несколько сотен килограмм.

0 голосов
/ 20 декабря 2010

Рассмотрите возможность буферизации выходного потока

0 голосов
/ 20 декабря 2010

Питер,

Когда что-то кажется слишком хорошим, чтобы быть правдой, это обычно так.89 мсек для записи 40 МБ данных предполагают, что полоса пропускания вашего жесткого диска намного больше 500 МБ / с (поскольку вы также указали время для открытия и закрытия файла).Это вряд ли будет правдой.Вы проверяли, что файл на самом деле имеет размер 40 МБ.Кроме того, я бы предложил, чтобы вы инициировали буфер, чтобы увидеть содержимое файла не всех нулей.Может быть, нетронутый буфер просто пропущен.Что бы это ни было, число, которое вы имеете, слишком хорошо, чтобы быть правдой.

Спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...