Не используйте System.out.println в коде на стороне сервера
Я слышал, что с помощью System.out.println
для целей регистрации это очень плохая практика, и это может привести к сбою сервера.
Я не использую этот подход, но мне очень интересно знать, почему System.out.println может создавать такие ненужные вещи при использовании в бэкэнд-коде.
9 ответов
System.out.println является операцией ввода-вывода и поэтому занимает много времени. Проблема с использованием его в вашем коде состоит в том, что ваша программа будет ждать, пока печать не закончится. Это может не быть проблемой для небольших сайтов, но как только вы получите нагрузку или много итераций, вы почувствуете боль.
Лучшим подходом является использование каркаса логирования. Они используют очередь сообщений и пишут только в том случае, если нет других выходных данных.
Еще одним преимуществом является то, что вы можете настроить отдельные файлы журнала для разных целей. Что-то, за что ваша команда Ops будет любить вас.
Узнайте больше здесь:
Ознакомьтесь со статьей Адама Бинса в выпуске журнала Java Magazine за ноябрь / декабрь о стресс-тестировании приложений JEE6 - это бесплатно онлайн, вам нужно только подписаться на него.
На странице 43 он показывает, что серверное приложение, которому удается обрабатывать 1700 транзакций в секунду, падает до 800 при вставке одного System.out.println
с фиксированной строкой в каждом.
Это плохая практика, потому что когда ваше приложение идет в производство, вы не можете отделить журналы приложений от журналов сервера.
Команды разработчиков хотят, чтобы вы отделяли журналы, созданные вашим приложением, от журналов на сервере приложений (tomcat, websphere и т. Д.): Они хотят иметь возможность контролировать сервер приложений независимо от самого приложения.
Более того, используя System.out, вы не можете определить уровень журнала: в Production вы не хотите печатать отладочную информацию.
Это считается плохим, потому что System.out.println();
съедает больше ресурсов процессора и, следовательно, вывод идет медленно, что ухудшает производительность. (Фактически каждая операция ввода-вывода потребляет процессор).
Причина не в том, что сервер может выйти из строя, но может быть трудно найти такой вывод на сервере. Вы всегда должны использовать какую-то структуру логирования с определенным поведением и выходным файлом.
Например, наличие нескольких запросов на вашем сервере и печать журнала System.out
не очень хорошая практика
- Все журналы выводятся на экран (дескриптор файла). Нет способа прокрутить назад и прочитать журнал.
System.out
не синхронизирован Должно быть управление параллелизмом, чтобы управлять печатью черезSystem.out
- Вы не можете определить уровни журнала через
System.out
, Вы не можете разделить свои уровни журнала, чтобы отделить выходы на лету.
Надеюсь, это поможет.
- Программа будет ждать окончания печати. Регистраторы используют очередь сообщений и пишут только в том случае, если нет других выходных данных.
- System.out.println (SOP) не являются потокобезопасными (то есть асинхронными). Регистраторы являются потокобезопасными (то есть синхронными).
- Регистраторы легко настраиваются
a.
Форматирование, ограничение содержимого журнала, достижимое регистраторамиb.
Регистрация в нескольких местах назначения - файл, консоль, БД - СОП записывают журналы в файлы журналов Сервера. Мы должны хранить журналы приложений отдельно от журналов сервера, так как это может привести к отказу сервера
- Серверные приложения, которым удается обрабатывать 1700 транзакций в секунду, уменьшаются до 800 при вставке одиночных СОП с фиксированной строкой в каждом
Еще одна причина состоит в том, что System.out и err являются PrintStreams, которые потребляют все лежащие в основе исключения IOException. Смотрите эти методы PrintStreams:
/**
* Writes the specified byte to this stream. If the byte is a newline and
* automatic flushing is enabled then the <code>flush</code> method will be
* invoked.
*
* <p> Note that the byte is written as given; to write a character that
* will be translated according to the platform's default character
* encoding, use the <code>print(char)</code> or <code>println(char)</code>
* methods.
*
* @param b The byte to be written
* @see #print(char)
* @see #println(char)
*/
public void write(int b) {
try {
synchronized (this) {
ensureOpen();
out.write(b);
if ((b == '\n') && autoFlush)
out.flush();
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
/**
* Flushes the stream and checks its error state. The internal error state
* is set to <code>true</code> when the underlying output stream throws an
* <code>IOException</code> other than <code>InterruptedIOException</code>,
* and when the <code>setError</code> method is invoked. If an operation
* on the underlying output stream throws an
* <code>InterruptedIOException</code>, then the <code>PrintStream</code>
* converts the exception back into an interrupt by doing:
* <pre>
* Thread.currentThread().interrupt();
* </pre>
* or the equivalent.
*
* @return <code>true</code> if and only if this stream has encountered an
* <code>IOException</code> other than
* <code>InterruptedIOException</code>, or the
* <code>setError</code> method has been invoked
*/
public boolean checkError() {
if (out != null)
flush();
if (out instanceof java.io.PrintStream) {
PrintStream ps = (PrintStream) out;
return ps.checkError();
}
return trouble;
}
Таким образом, IOException из базового потока используется ВСЕГДА, и обычно люди никогда не вызывают checkError в System out, поэтому они даже не знают, что что-то случилось.
Использование Standard Out - плохая практика. Однако, если у вас есть библиотека или код, который использует System.out и System.err, вы можете написать свой собственный PrintStream, который вместо этого записывает в журнал имя потока и info() и error() текст. После того, как вы это сделаете, вы можете более спокойно использовать System.out, поскольку он будет записывать в журналы, например, log4j.
В идеале вы должны использовать правильные журналы непосредственно для регистрации уровня отладки. ИМХО, это не имеет большого значения, если вы не используете встроенный System.out/err! (Большое предположение по общему признанию)
Независимо от того, используете ли вы System.out, который перенаправлен в файл, или используете log4j или Java Logger для записи в файл, производительность практически одинакова.