#java #xml #многопоточность #парсер
структура xml довольно простая... Но размер файла довольно большой.... Хочется читать файл в несколько параллельных потоков... Как в несколько потоков прочитать ОГРОМНЫЙ xml файл? какой парсер вы бы посоветовали ? UPD: Файл имеет не сложную структуру... сильной вложенности нет... Кусочек файла:К сожалению, этот xml формируется не в нашей компании (у клиентов)... Доступа к базам данных(4 разных типа БД) на стороне клиента у нас нет, и быть не может, по соображениям политики безопасности в области информации и чего-то там(одним словом - гос.контора )... У заказчика нет специалистов и желания переписывать свой софт, который собирает данные из таблиц разных БД и формирует этот xml. ... ... ... ... ... ...
Ответы
Ответ 1
Файлы формата XML, как и любых других LL(n)-подобных грамматик, невозможно читать в несколько потоков. Максимум что вы можете сделать - это сразу после получения данных передавать их в другой поток на обработку, чтобы 1 поток всегда был занят парсингом. К примеру, если на разбор файла уходит половина времени, и еще половина - на запись в БД, то вынесение работы с БД в другой поток ускорит процесс в два раза. Здесь вам может пригодиться класс java.util.concurrent.BlockingQueue и паттерн "производитель-потребитель" (Producer-Consumer)Ответ 2
Мне кажется, что многопоточность не решит проблему... Вы же читаете файл с одного ЖД=> запустив N потоков, вы упретесь в производительность ЖД. Как вариант, можно читать непрерывно одним потоком в память, а обрабатывать данные в несколько потоков. Вроде, паттерн зовет производитель/потребитель. А почему XML файл может достигать таких размеров? Может быть возможно отказаться от XML, а разместить данные по сущностям в БД? На мой взгляд, такой размер файла-это не нормально...Ответ 3
В принципе, файл такой структуры легко "парсится в параллель". Определяете его размер и делите на число потоков-обработчиков. Таким образом каждый поток знает позицию в файле с которой ему надо начать обработку и где ее заканчивать. Все потоки (кроме первого) позиционируются в нужную точку файла и далее читают файл построчно. После того, как прочитана строка с (т.е. закрывающий тег для части файла, обрабатываемой предыдущим потоком) начинается построчная обработка своей части. Она завершется, когда поток прочел строку с в позиции после конца своей части. Понятно, что алгоритм поиска начала обработки для первого и конца обработки для последнего потоков некоторым (надеюсь, очевидным) образом отличны от вышеописанных. Как именно "подсунуть" в библиотеку парсинга на Java самостоятельно выделяемые фрагменты, извините, не знаю. Лично я (наверное) распарсил бы их сам, поскольку структура тривиальна. Даст ли такая потоковая обработка прирост производительности? Не очевидно (поскольку чтение с одного и того же диска), но вполне возможно (imho за счет распараллеливания запросов на обновление базы данных (однако, это уже сильно зависит от конкретной базы)).Ответ 4
Некоторой альтернативой SAX-парсеру может стать pull-парсер: http://www.scala-lang.org/api/2.7.4/scala/xml/pull/XMLEventReader.html (он из Scala, но из Джавы тоже получится использовать) Впрочем, вряд ли он сам по себе даст действительно большой выигрыш в скорости. Вообще, возможна следующая идея - читать этот файл не последовательно, а из нескольких позиций одновременно (скажем, первый гигабайт читается в первом потоке, второй - во втором и так далее). Тебе в этом может помочь https://docs.oracle.com/javase/7/docs/api/java/nio/channels/FileChannel.html (главное, не начни читать посреди xml-тега). Это непроверенная идея, никогда её не реализовывал. Но она может помочь, т.к. обычно самым большим bottleneck-ом является чтение с диска.Ответ 5
Есть класс RandomAccessFile. Может читать файл с определённого байта. //r- read, файл открыт только для чтения RandomAccessFile raf = new RandomAccessFile("input.txt", "r"); // «курсор» стоит на 0-м символе. String text1 = raf.readLine(); //перемещаем «курсор» на 100-й символ. raf.seek(100); String text2 = raf.readLine(); //перемещаем «курсор» на 0-й символ. raf.seek(0); String text3 = raf.readLine(); //закрываем файл raf.close();
Комментариев нет:
Отправить комментарий