Java: В чем причина такой медленной работы System.out.println ()? - PullRequest
9 голосов
/ 04 июня 2009

Для небольших логических программ, которые можно сделать в текстовом редакторе, для трассировки я использую классическую System.out.println().

Полагаю, вы все знаете, как сложно использовать это в блоке большого числа итераций. Почему это так медленно? В чем причина этого?

Ответы [ 9 ]

33 голосов
/ 04 июня 2009

Это не имеет ничего общего с JVM. Печать текста на экране просто требует от ОС большой работы по отрисовке букв и особенно прокрутки. Если вы перенаправите System.out в файл, это будет намного быстрее.

12 голосов
/ 04 июня 2009

Это очень зависит от ОС. Например, в Windows запись в консоль - это операция блокировки, а также она медленная, поэтому запись большого количества данных в консоль замедляет (или блокирует) ваше приложение. В операционных системах Unix-типа запись в консоль буферизуется, поэтому ваше приложение может продолжать разблокироваться, и консоль наверстывает упущенное.

5 голосов
/ 04 июня 2009

Да, при записи в консоль огромные накладные расходы. Гораздо больше, чем требуется для записи в файл или сокет. Также, если имеется большое количество потоков, все они конкурируют в одной и той же блокировке. Я бы порекомендовал использовать что-то другое, что System.out.println для трассировки.

3 голосов
/ 04 июня 2009

Это не имеет ничего общего с Java и JVM, но с консольным терминалом. В большинстве операционных систем, которые я знаю, запись в консоли выводится медленно.

2 голосов
/ 20 ноября 2009

Буферизация может очень помочь. Попробуйте это:

System.setOut( new PrintStream(new BufferedOutputStream(System.out)) );

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

System.out.flush();
1 голос
/ 12 июня 2009

Одна интересная вещь, которую я заметил о записи в терминал (по крайней мере, в Windows). Это на самом деле работает намного быстрее, если окно свернуто. Это определенно тесно связано с ответом Майкла Боргвардта о рисовании и прокрутке. Действительно, если вы регистрируетесь достаточно, чтобы заметить замедление, вам, вероятно, лучше записать в файл.

1 голос
/ 04 июня 2009

Может показаться, что это не дает прямого ответа на ваш вопрос, но я советую никогда не использовать System.out для трассировки (если вы подразумеваете под этим отладку, чтобы просто увидеть продвижение вашего приложения)

Проблем с System.out для отладки несколько:

  • как только приложение заканчивается, когда вы закрываете консоль, вы теряете журнал

  • вы должны будете удалить эти операторы, когда ваше приложение будет работать должным образом (или прокомментировать их). Позже, если вы захотите снова активировать их, вам придется снова раскомментировать / комментировать ... утомительно

Я рекомендую вместо этого использовать log4j и "смотреть" файл журнала, либо с помощью команды tail - есть также Tail для Windows - либо с плагином Eclipse, например LogWatcher .

1 голос
/ 04 июня 2009

Некоторые терминалы просто быстрее других. Это может варьироваться даже в пределах одной операционной системы.

0 голосов
/ 12 июня 2009

Медлительность обусловлена ​​большим количеством переходов Java-Native, которые происходят при каждом разрыве строки или сбросе. Если в итерации много шагов, System.out.println () не очень помогает. Если шаги итерации сами по себе не так важны, вы можете вызывать System.out.println () только на каждые 10 или 100 шагов. Вы также можете обернуть System.out в BufferedOutputStream. И, конечно, всегда есть возможность асинхронизировать печать через ExecutorService.

...