Подтвердить что ты не робот

Является ли java.util.Scanner медленным?

В приложении Android я хочу использовать класс Scanner для чтения списка поплавков из текстового файла (это список вершинных координат для OpenGL). Точный код:

Scanner in = new Scanner(new BufferedInputStream(getAssets().open("vertexes.off")));
final float[] vertexes = new float[nrVertexes];
for(int i=0;i<nrVertexFloats;i++){
    vertexes[i] = in.nextFloat();
}

Кажется, что это невероятно медленно (потребовалось 30 минут, чтобы прочитать 10 000 поплавков!) - как проверено на эмуляторе 2.1. Что происходит? Я не помню, чтобы Scanner был таким медленным, когда я использовал его на ПК (правда, я никогда раньше не читал более 100 значений). Или это что-то еще, например, чтение из потока ввода активов?

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

4b9b3361

Ответ 1

Не знаю об Android, но, по крайней мере, на JavaSE, сканер работает медленно.

Внутри, сканер делает преобразование UTF-8, которое бесполезно в файле с поплавками.

Поскольку все, что вы хотите сделать, это читать поплавки из файла, вы должны пойти с пакетом java.io.

Ребята из SPOJ борются со скоростью ввода-вывода. Это сайт польского конкурса программистов с очень сложными проблемами. Их отличие состоит в том, что они принимают более широкий спектр языков программирования, чем другие сайты, и во многих своих проблемах вход настолько велик, что если вы не пишете эффективные операции ввода-вывода, ваша программа будет лопнуть срок.

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

Конечно, я советую не писать собственный флоатор-парсер, но если вам нужна скорость, это еще решение.

Ответ 2

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

scanner.nextFloat();

с

Float.parseFloat(scanner.next());

почти в 7 раз быстрее.

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

В большинстве случаев (если не все) next* используют обычные выражения по той же причине, поэтому, если вы знаете структуру своих данных, предпочтительнее всегда использовать next() и анализировать результат. И.Е. также используйте Double.parseDouble(scanner.next()) и Integer.parseInt(scanner.next()).

Соответствующий источник: https://android.googlesource.com/platform/libcore/+/master/luni/src/main/java/java/util/Scanner.java

Ответ 3

Для Spotify Challenge они написали небольшую утилиту java для синтаксического анализа IO быстрее: http://spc10.contest.scrool.se/doc/javaio Утилита называется Kattio.java и использует BufferedReader, StringTokenizer и Integer.parseInt/Double.parseDouble/Long.parseLong для чтения чисел.

Ответ 4

Очень проницательный пост. Обычно, когда я работал с Java, мысль Scanner была самой быстрой на ПК. То же самое, когда я пытаюсь использовать его в AsyncTask на Android, его WORST.

Я думаю, что Android должен придумать альтернативу сканеру. Я использовал scanner.nextFloat(); и scanner.nextDouble(); и scanner.nextInt(); все вместе, что сделало мою жизнь больной. После того, как я проверил свое приложение, выяснилось, что виновник сидит скрытно.

Я изменил на Float.parseFloat(scanner.next()); аналогично Double.parseDouble(scanner.next()); и Integer.parseInt(scanner.next());, что, безусловно, сделало мое приложение довольно быстрым, я должен согласиться, быстрее 60%.

Если кто-то испытал то же самое, напишите здесь. И я слишком смотрю на альтернативу API Scanner, у любого есть яркие идеи, которые могут появляться и размещаться здесь при чтении форматов файлов.

Ответ 5

Да, я не вижу ничего подобного. Я могу читать около 10 М, плавающих таким образом через 4 секунды на рабочем столе, но это просто не может быть так.

Я пытаюсь думать о других объяснениях - возможно ли, что он блокирует чтение входного потока из getAssets()? Я мог бы попробовать полностью прочитать этот ресурс, выбрав время, а затем посмотрев, сколько времени потребуется для сканирования.

Ответ 6

Scanner может быть частью проблемы, но вам нужно профилировать свой код, чтобы знать. Альтернативы могут быть быстрее. Вот простой тест, сравнивающий Scanner и StreamTokenizer.

Ответ 7

У меня точно такая же проблема. Потребовалось 10 минут, чтобы прочитать мой файл размером 18 КБ. В конце я написал настольное приложение, которое преобразует эти считываемые человеком числа в машиночитаемый формат, используя DataOutputStream.

Результат был поразительным.

Btw, когда я его отслеживал, большинство вызовов метода Scanner включает регулярные выражения, реализация которых обеспечивается пакетами com.ibm.icu.** (проект IBM ICU). Это действительно излишне.

То же самое касается String.format. Избегайте его в Android!