Является ли java.util.Scanner медленным? - PullRequest
16 голосов
/ 15 марта 2010

В приложении для 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 минут, чтобы прочитать 10000 операций с плавающей запятой!) - как было протестировано на эмуляторе 2.1. В чем дело? Я не помню, чтобы сканер работал так медленно, когда я использовал его на ПК (честно говоря, я никогда не читал более 100 значений раньше). Или это что-то еще, например чтение из потока ввода ресурсов?

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

Ответы [ 7 ]

22 голосов
/ 12 декабря 2010

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

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

8 голосов
/ 15 марта 2010

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

Внутренне Scanner выполняет преобразование UTF-8, что бесполезно в файле с плавающей точкой.

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

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

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

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

2 голосов
/ 16 октября 2011

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

1 голос
/ 19 июня 2014

Очень проницательный пост. Обычно, когда я работал с 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% быстрее.

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

0 голосов
/ 15 апреля 2010

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

Результат был удивительным.

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

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

0 голосов
/ 15 марта 2010

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

0 голосов
/ 15 марта 2010

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

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

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