Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> RandomAccessFile Скорость записи 
V
    Опции темы
Mirkes
Дата 19.3.2014, 19:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 586
Регистрация: 18.8.2011
Где: Красноярск

Репутация: 7
Всего: 17



Мне нужен быстрый доступ к отдельным значениям в большом бинарном файле. Решил использовать RandomAccessFile.
Тут же возникла проблема - запись файла из старого формата в новый работает с потрясающей скоростью. Вот полный текст перекодировки:
Код

            for (int row = 0; row < nRow; row++) {
                for (int col = 0; col < nCol; col++) {
                    d = getData(noData, line);
                    if (d == Double.POSITIVE_INFINITY) {
                        pb.stop();
                        return;
                    }
                    raf.writeDouble(d);
                    //Define min and max!
                    if (!Double.isNaN(d)){
                        if (d<minV)
                            minV=d;
                        if (d>maxV)
                            maxV=d;
                    }
                }
            }


Файл большой nRow=8082, nCol=14090. Это спутниковый снимок в некоем странном текстовом формате.
В методе getData происходит чтение другого, текстового, файла и конвертация в числовую форму.
pb не работает с файлами.
В том виде, в котором программа приведена выше время обработки одного файла 38 минут
Если закомментировать строку с raf то время работы 19 секунд.
Запись производится подряд. Конечно, пишется 869М, но не с такой же тормознутостью.
Или это свойство RandomAccessFile?
К сожалению после завершения записи файла мне надо дописать пару значений в начало файла, так что RandomAccessFile вроде по существу.

Что посоветуете? Как ускорить работу?


--------------------
Mirkes
PM MAIL   Вверх
Pawl
Дата 19.3.2014, 21:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 649
Регистрация: 22.4.2008
Где: Витебск

Репутация: 7
Всего: 28



Цитата(Mirkes @  19.3.2014,  19:44 Найти цитируемый пост)
Что посоветуете?

Цитата

From the docs, rws mode means:
Open for reading and writing, as with "rw", and also require that every update to the file's content or metadata be written synchronously to the underlying storage device.
It stands to reason that forcing the file's content to be written to the underlying device would be significantly slower than the other methods, which probably allow the VM/OS to cache the writes.

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

Это сообщение отредактировал(а) Pawl - 19.3.2014, 21:33


--------------------
В действительности всё совсем не так, как на самом деле
PM MAIL   Вверх
Mirkes
Дата 19.3.2014, 22:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 586
Регистрация: 18.8.2011
Где: Красноярск

Репутация: 7
Всего: 17



To Pawl Спасибо, приблизительно это и реализовал.
Фактически я сделал запись в DataOutputStream а потом переоткрыл его как RandomAccessFile и дописал оставшиеся два значения. Открывал как "rw". Из документации мне показалось, что это быстрее чем rws и rwd.
В результате замены типа выходного потока время уменьшилось до 6.25 минуты, что уже приемлемо (нужно сконвертировать 12 файлов).

Однако мне все равно не понятно, почему при файле открытом как 
Код

            raf = new RandomAccessFile(fNameOut, "rw");


запись идет в 5 раз медленнее чем в файле, открытом как
Код

            DataOutputStream dos = new DataOutputStream(new FileOutputStream(fNameOut));

 Кстати только что заметил, что и ПОСЛЕДОВАТЕЛЬНОЕ чтение из файла открытого
Код

            raf = new RandomAccessFile(fNameOut, "r");

идет жутко медленно. Гораздо медленнее чем из текстового файла со все его парсингом и т.п. Засек точное время. Даже с заменой способа чтения на DataInputStream чтение всего файла заняло около 10 минут. 

Мне просто интересно, это принципиальная особенность файлов прямого доступа?
Или так сильно тормозит приведение каждого double к некоему переносимому стандарту java при записи и соответственно обратное преобразование при чтении?

Попробую сформулировать задачу иначе.
Есть большой текстовый файл (14000 столбцов и 8000 строк, что-то чуть больше 100 миллионов значений). Таких файлов 12.
К файлу есть два варианта запроса.
1. Прочитать все данные для формирования картинки на экране. Нужно пару раз на каждый файл. В принципе если плюнуть на все и просто парсить текстовый файл то это займет около 1 минуты. Не фонтан, но терпимо.
2. Указать значение с определенными координатами. Порядка 30,000 запросов на файл при условии, что повторных обработок не будет.

Ограничение на хранение массива в памяти очевидно. На массив нужно что-то около 800М памяти.
Исходя из второй задачи я предполагал, что конвертация в бинарный файл даст приличный выигрыш при дальнейших запросах, однако получается, что для создания картинки точно лучше читать прямо текстовый файл (1 минута против 10 из бинарного).
К сожалению пока не закончил вторую часть и не могу сказать сколько займет выполнение тех 30,000 запросов по координатам.

Как наиболее организовать быструю работу с файлом?
Может без интерфейсов DataOutput и DataInput работа с файлом пойдет быстрее? Переносить конвертированные файлы я не собираюсь.

Таким образом окончательная формулировка вопроса:
Какой тип работы с файлами Вы порекомендуете для этой задачи?

Это сообщение отредактировал(а) Mirkes - 19.3.2014, 22:41


--------------------
Mirkes
PM MAIL   Вверх
LSD
Дата 20.3.2014, 11:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 210
Всего: 538



Я бы рекомендовал memory mapped file.
Код

        RandomAccessFile raf = new RandomAccessFile("file", "rw");
        MappedByteBuffer buffer = raf.getChannel().map(FileChannel.MapMode.READ_WRITE, 0L, raf.length());
        DoubleBuffer doubleBuffer = buffer.asDoubleBuffer();
        // work with file
        buffer.force();
        raf.close();



--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
Mirkes
Дата 20.3.2014, 12:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 586
Регистрация: 18.8.2011
Где: Красноярск

Репутация: 7
Всего: 17



Цитата(LSD @  20.3.2014,  11:29 Найти цитируемый пост)
Я бы рекомендовал memory mapped file.

Спасибо. Попробую.

Попробовал и ничего не понял.
Вот код
Код

            raf = new RandomAccessFile(fNameOut, "rw");
            raf.setLength(((long)(HEAD+nCol*nRow))*DBL_SIZE);
            MappedByteBuffer buffer = raf.getChannel().map(FileChannel.MapMode.READ_WRITE, 0L, raf.length());
            DoubleBuffer doubleBuffer = buffer.asDoubleBuffer();

размер файла 911 003 096 байт. Файл создан именно такого размера.

В ответ получил
Код

java.io.IOException: Map failed
    at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:748)
    at geodata.GISLayer.<init>(GISLayer.java:102)
    at client.Geologic$1$1.run(Geologic.java:233)
    at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.OutOfMemoryError: Map failed
    at sun.nio.ch.FileChannelImpl.map0(Native Method)
    at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:745)
    ... 3 more

Программа запускалась с опцией
-Xmx1600m

Так что даже в heap должно быть достаточно памяти для отображения, хотя, как я прочитал, память выделяется за пределами heap.

Может нужно указать еще какие-то опции для взятия памяти?

Это сообщение отредактировал(а) Mirkes - 20.3.2014, 12:37


--------------------
Mirkes
PM MAIL   Вверх
LSD
Дата 21.3.2014, 11:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 210
Всего: 538



Для memory mapped file не требуется памяти в полном объеме. Поэтому размер хипа как раз не важен.
Я думаю скорее всего закончилось адресное пространство процесса, и файл просто некуда мапить. У тебя ОС и JVM какие 32/64 битные?


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
Mirkes
Дата 21.3.2014, 11:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 586
Регистрация: 18.8.2011
Где: Красноярск

Репутация: 7
Всего: 17



ОС Windows 7 Enterprice SP1 64bit
RAM 8G

IDE JDeveloper 11.1.2.4
Java™ Platform    1.6.0_24

JRE 1.5.0_45   32bit

Забавно, JDK и JRE разные. JRE обновляется автоматически, а JDK видимо нужно обновлять вручную



--------------------
Mirkes
PM MAIL   Вверх
LSD
Дата 21.3.2014, 12:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 210
Всего: 538



Цитата(Mirkes @  21.3.2014,  12:39 Найти цитируемый пост)
32bit

У 32-х битного процесса адресное пространство 2Gb. У тебя файл 900Mb, да еще и куча 1600Mb, явно больше 2Gb.


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
Mirkes
Дата 21.3.2014, 13:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 586
Регистрация: 18.8.2011
Где: Красноярск

Репутация: 7
Всего: 17



Если я правильно понял, то воспользоваться отображенными файлами я смогу только перейдя на 64bit-ую Java?

Спасибо за помощь.


--------------------
Mirkes
PM MAIL   Вверх
LSD
Дата 21.3.2014, 17:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Leprechaun Software Developer
****


Профиль
Группа: Модератор
Сообщений: 15718
Регистрация: 24.3.2004
Где: Dublin

Репутация: 210
Всего: 538



Цитата(Mirkes @  21.3.2014,  14:44 Найти цитируемый пост)
Если я правильно понял, то воспользоваться отображенными файлами я смогу только перейдя на 64bit-ую Java?

Нет, просто надо понимать, что чтобы использовать гигабайтный MMF сама JVM (куча+служебные области) должна занимать менее гигабайта. Простейший тест спокойно мапит гигабайтный файл, вопрос сколько у тебя в конкретном случае остается памяти.


--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
PM MAIL WWW   Вверх
Mirkes
Дата 21.3.2014, 17:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 586
Регистрация: 18.8.2011
Где: Красноярск

Репутация: 7
Всего: 17



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

Еще раз спасибо.


--------------------
Mirkes
PM MAIL   Вверх
Pawl
Дата 27.3.2014, 12:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 649
Регистрация: 22.4.2008
Где: Витебск

Репутация: 7
Всего: 28



Пардон, что пишу в закрытую тему, нашел способ добавить в начало файла данные при помощи java.nio. Если вам интересно, можете попробовать, протестировать скорость и т. д. smile 
Код

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Path;
import java.nio.file.Paths;

import static java.nio.file.Files.newByteChannel;
import static java.nio.file.StandardOpenOption.READ;
import static java.nio.file.StandardOpenOption.WRITE;

public class Inserter {
    public static void main(String... args) {
        String s = "I was here!\n";
        byte data[] = s.getBytes();
        ByteBuffer out = ByteBuffer.wrap(data);
        Path file = Paths.get("BrasilOpen.txt");
        try (SeekableByteChannel fc = (newByteChannel(file, READ, WRITE))) {
            // Write "I was here!" at the beginning of the file.
            fc.position(0);
            while (out.hasRemaining())
                fc.write(out);
        } catch (IOException x) {
            System.out.println("I/O Exception: " + x);
        }
    }
}


Это сообщение отредактировал(а) Pawl - 27.3.2014, 17:27


--------------------
В действительности всё совсем не так, как на самом деле
PM MAIL   Вверх
Mirkes
Дата 27.3.2014, 13:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 586
Регистрация: 18.8.2011
Где: Красноярск

Репутация: 7
Всего: 17



Цитата(Pawl @  27.3.2014,  12:48 Найти цитируемый пост)
Пардон, что пишу в закрытую тему, нашел способ добавить в начало файла данные при помощи java.nio. Если вам интересно, можете попробовать, протестировать скорость и т. д.  

Спасибо.
На самом деле это интересно, но свою проблему я решил. Не быстро, но решил.
Основной ступор был в том, что поднять на мозги весь файл было слишком накладно. А когда я пробовал еще что-то делать получал переполнение памяти. Посему я и хотел получить прямой доступ. А прямой доступ без отображения в память оказался очень медленным. А на отображение в память - нет места. И получил замкнутый круг.
На самом деле я решил достаточно просто - сначала записал без прямого доступа положив на место пока неизвестных параметров заглушки, потом переоткрыл файл с прямым доступом и записал вычисленные параметры на место.
Далее использовал прямой доступ.
Когда появится время (если появится) попробую поэкспериментировать с разными типами файлового ввода=вывода и их скоростью.
Спасибо за совет.


--------------------
Mirkes
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0848 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.